home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / machserver / 1.098 / fspdev / fspdevSrv.c < prev    next >
C/C++ Source or Header  |  1991-06-26  |  84KB  |  2,534 lines

  1. /* 
  2.  * fspdevSrv.c --  
  3.  *
  4.  *    This file contains routines directly related to the request-response
  5.  *    protocol between the client and server processes.  Routines that
  6.  *    setup state, i.e. the SrvOpen, CltOpen, and migration routines,
  7.  *    are in fsPdevSetup.c.  Routines for the Control stream are
  8.  *    found in fsPdevControl.c
  9.  *
  10.  *    Operations on a pseudo-device are forwarded to a user-level server
  11.  *    process using a "request-response" protocol.
  12.  *    The server process declares a request buffer (and optionally a read
  13.  *    ahead buffer) in its address space.  The kernel puts requests, which
  14.  *    are generated when a client does an operation on the pseudo stream,
  15.  *    into the request buffer directly.  The server learns of new requests
  16.  *    by reading messages from the server stream that contain offsets within
  17.  *    the request buffer.  Write requests may not require a response from
  18.  *    the server.  Instead the kernel just puts the request into the buffer
  19.  *    and returns to the client.  This allows many requests to be buffered
  20.  *    before a context switch to the server process.  Similarly,
  21.  *    the server can put read data into the read ahead buffer for a pseudo
  22.  *    stream.  In this case a client's read will be satisfied from the
  23.  *    buffer and the server won't be contacted.
  24.  *
  25.  * Copyright 1987, 1988 Regents of the University of California
  26.  * Permission to use, copy, modify, and distribute this
  27.  * software and its documentation for any purpose and without
  28.  * fee is hereby granted, provided that the above copyright
  29.  * notice appear in all copies.  The University of California
  30.  * makes no representations about the suitability of this
  31.  * software for any purpose.  It is provided "as is" without
  32.  * express or implied warranty.
  33.  */
  34.  
  35. #ifndef lint
  36. static char rcsid[] = "$Header: /sprite/src/kernel/fspdev/RCS/fspdevSrv.c,v 9.7 91/06/26 01:06:56 mottsmth Exp $ SPRITE (Berkeley)";
  37. #endif not lint
  38.  
  39. #include <status.h>
  40. #include <sprite.h>
  41. #include <fs.h>
  42. #include <fsutil.h>
  43. #include <fsNameOps.h>
  44. #include <fsio.h>
  45. #include <fsconsist.h>
  46. #include <fsioLock.h>
  47. #include <fsdm.h>
  48. #include <fsStat.h>
  49. #include <fspdev.h>
  50. #include <proc.h>
  51. #include <rpc.h>
  52. #include <string.h>
  53.  
  54. /*
  55.  * Prevent tracing by defining CLEAN here before this next include
  56.  */
  57. #undef CLEAN
  58. #include <fspdevInt.h>
  59. #include <dev/pfs.h>
  60.  
  61. /*
  62.  * Access to Fspdev_ServerIOHandle is monitored to serialize access to
  63.  * the request-response communication channel.
  64.  */
  65. #define LOCKPTR (&pdevHandlePtr->lock)
  66.  
  67. /*
  68.  * Flags for a pseudo device handle.
  69.  *    PDEV_SETUP        The server has set up state for the stream.
  70.  *    PDEV_BUSY        Set during request-response to ensure that
  71.  *                only one client process is using the stream.
  72.  *    PDEV_REPLY_READY    The server gave us a reply
  73.  *    PDEV_REPLY_FAILED    There was some problem (usually with copy in)
  74.  *                getting the reply from the server.
  75.  *    PDEV_SERVER_GONE    Set after the server closes its stream.
  76.  *    PDEV_READ_BUF_EMPTY    When set there is no data in the read ahead
  77.  *                buf.
  78.  *    PDEV_SERVER_KNOWS_IT    Set after the server has done a read and been
  79.  *                told that we too think the read ahead buffer
  80.  *                is empty.  This synchronization simplifies
  81.  *                things; there is no wrapping; there is no
  82.  *                confusion about full vs. empty.
  83.  *    PDEV_READ_PTRS_CHANGED    Set when we have used data from the read
  84.  *                ahead buffer.  This makes the server stream
  85.  *                selectable so it will find out about the
  86.  *                new pointers.
  87.  *    PDEV_WRITE_BEHIND    Write-behind is enabled for this stream.
  88.  *    PDEV_NO_BIG_WRITES    Causes writes larger than will fit into
  89.  *                the request buffer to fail.  This is to
  90.  *                support UDP socket semantics, sigh.
  91.  *    PDEV_NAMING        Set on the naming request-response channel.
  92.  *    PDEV_REQUEST_ABORTED    Set when the client aborts during a request-
  93.  *                response transaction so we ignore the next rply.
  94.  *    FS_USER_IN/OUT        These flags are borrowed from the stream flags
  95.  *                and indicate which buffers are in user space
  96.  */
  97. #define PDEV_SETUP        0x0001
  98. #define PDEV_BUSY        0x0002
  99. #define PDEV_REPLY_READY    0x0004
  100. #define PDEV_REPLY_FAILED    0x0008
  101. #define PDEV_SERVER_GONE    0x0010
  102. #define PDEV_READ_BUF_EMPTY    0x0020
  103. #define PDEV_SERVER_KNOWS_IT    0x0040
  104. #define PDEV_READ_PTRS_CHANGED    0x0080
  105. #define PDEV_WRITE_BEHIND    0x0100
  106. #define PDEV_NO_BIG_WRITES    0x0200
  107. #define PDEV_NAMING        0x0400
  108. #define PDEV_REQUEST_ABORTED    0x0800
  109. /*resrv FS_USER_IN        0x8000 */
  110. /*resrv FS_USER_OUT          0x800000 */
  111.  
  112. /*
  113.  * Forward declarations.
  114.  */
  115.  
  116. static ReturnStatus RequestResponse _ARGS_((
  117.     Fspdev_ServerIOHandle *pdevHandlePtr,
  118.     int hdrSize, register Pdev_RequestHdr *requestHdrPtr, int inputSize,
  119.     Address inputBuf, int replySize, Address replyBuf, 
  120.     Fs_IOReply *ioReplyPtr, Sync_RemoteWaiter *waitPtr));
  121. static void PdevClientWakeup _ARGS_((Fspdev_ServerIOHandle *pdevHandlePtr));
  122. static void PdevClientNotify _ARGS_((Fspdev_ServerIOHandle *pdevHandlePtr));
  123.  
  124. /*
  125.  *----------------------------------------------------------------------
  126.  *
  127.  * RequestResponse --
  128.  *
  129.  *    The general request-response protocol between a client's pseudo
  130.  *    stream and the server stream.  This passes a request to the server
  131.  *    that specifies the command and parameters, the size of the input data
  132.  *    and the max size of the reply.  Then, if a reply is needed, this blocks
  133.  *    the client until the server responds.
  134.  *
  135.  * Results:
  136.  *    An error code from the server, or from errors on the vm copies.
  137.  *
  138.  * Side effects:
  139.  *    The server process is locked while we copy the request into the
  140.  *    buffer in the server's address space.  The firstByte and lastByte
  141.  *    offsets into the pseudo stream request buffer are updated to
  142.  *    reflect the new request.  The corresponding server stream is
  143.  *    marked FS_READABLE.
  144.  *
  145.  *----------------------------------------------------------------------
  146.  */
  147.  
  148. INTERNAL static ReturnStatus
  149. RequestResponse(pdevHandlePtr, hdrSize, requestHdrPtr, inputSize, inputBuf,
  150.     replySize, replyBuf, ioReplyPtr, waitPtr)
  151.     register Fspdev_ServerIOHandle *pdevHandlePtr;    /* Caller should lock this
  152.                          * with the monitor lock. */
  153.     int            hdrSize;    /* Either sizeof(Pdev_Request) or
  154.                      * sizeof(Pfs_Request) */
  155.     register Pdev_RequestHdr *requestHdrPtr;    /* Caller fills in the
  156.                      * command and parameter parts. The
  157.                      * sizes are filled in here. */
  158.     int            inputSize;    /* Size of input buffer. */
  159.     Address        inputBuf;    /* Inputs of the remote command. */
  160.     int            replySize;    /* Size of output buffer.  0 means
  161.                      * no reply data expected.  If the
  162.                      * operation is PDEV_WRITE_ASYNC then no
  163.                      * reply is wanted and this is ignored*/
  164.     Address        replyBuf;    /* Results of the remote command. */
  165.     Fs_IOReply        *ioReplyPtr;    /* Amount transferred and signal to
  166.                      * return. (May be NIL if not needed.)*/
  167.     Sync_RemoteWaiter    *waitPtr;    /* Client process info for waiting.
  168.                      * Only needed for read & write. */
  169. {
  170.     register ReturnStatus  status;
  171.     Proc_ControlBlock       *serverProcPtr;   /* For VM copy operations */
  172.     register int       firstByte;         /* Offset into request buffer */
  173.     register int       lastByte;         /* Offset into request buffer */
  174.     int               room;         /* Room available in req. buf.*/
  175.     int               savedLastByte;    /* For error recovery */
  176.     int               savedFirstByte;   /*   ditto */
  177.  
  178.     if (ioReplyPtr != (Fs_IOReply *) NIL) {
  179.     ioReplyPtr->length = 0;
  180.     }
  181.  
  182.     if ((pdevHandlePtr == (Fspdev_ServerIOHandle *)NIL) ||
  183.     (pdevHandlePtr->flags & PDEV_SERVER_GONE)) {
  184.     return(DEV_OFFLINE);
  185.     } else if ((pdevHandlePtr->flags & PDEV_SETUP) == 0) {
  186.     panic( "RequestResponse: connection not set up\n");
  187.     }
  188.     /*
  189.      * See if we have to switch to a new request buffer.  This is needed
  190.      * to support UDP, which wants to set a maximum write size.  The max
  191.      * is implemented by letting the UDP server change the buffer size and
  192.      * setting the property that writes larger than the buffer fail.  We
  193.      * wait and switch after the request buffer empties.
  194.      */
  195.     firstByte = pdevHandlePtr->requestBuf.firstByte;
  196.     lastByte = pdevHandlePtr->requestBuf.lastByte;
  197.     if ((pdevHandlePtr->nextRequestBuffer != (Address)NIL) &&
  198.     ((firstByte > lastByte) || (firstByte == -1))) {
  199. #ifndef CLEAN
  200.     printf( "Switching to request buffer at 0x%x\n",
  201.                    pdevHandlePtr->nextRequestBuffer);
  202. #endif
  203.     pdevHandlePtr->requestBuf.data = pdevHandlePtr->nextRequestBuffer;
  204.     pdevHandlePtr->requestBuf.size = pdevHandlePtr->nextRequestBufSize;
  205.     pdevHandlePtr->nextRequestBuffer = (Address)NIL;
  206.     firstByte = -1;
  207.     }
  208.     /*
  209.      * FORMAT THE REQUEST HEADER.  Note that the complete message size is
  210.      * rounded up so subsequent messages start on word boundaries.
  211.      */
  212.     if (hdrSize == sizeof(Pdev_Request)) {
  213.     requestHdrPtr->magic = PDEV_REQUEST_MAGIC;
  214.     } else if (hdrSize == sizeof(Pfs_Request)) {
  215.     requestHdrPtr->magic = PFS_REQUEST_MAGIC;
  216.     } else {
  217.     panic( "RequestResponse: bad hdr size\n");
  218.     }
  219.     requestHdrPtr->requestSize = inputSize;
  220.     requestHdrPtr->replySize = replySize;
  221.     requestHdrPtr->messageSize = hdrSize +
  222.         ((inputSize + sizeof(int) - 1) / sizeof(int)) * sizeof(int);
  223.     if (pdevHandlePtr->requestBuf.size < requestHdrPtr->messageSize) {
  224.     printf("RequestResponse: request too large (%d > %d)\n",
  225.         requestHdrPtr->messageSize, pdevHandlePtr->requestBuf.size);
  226.     return(GEN_INVALID_ARG);
  227.     }
  228.  
  229.     PDEV_REQUEST_PRINT(&pdevHandlePtr->hdr.fileID, requestHdrPtr);
  230.     PDEV_REQUEST(&pdevHandlePtr->hdr.fileID, requestHdrPtr);
  231.  
  232.     /*
  233.      * PUT THE REQUEST INTO THE REQUEST BUFFER.
  234.      * We assume that our caller will not give us a request that can't all
  235.      * fit into the buffer.  However, if the buffer is not empty enough we
  236.      * wait for the server to catch up with us.  (Things could be optimized
  237.      * perhaps to wait for just enough room.  To be real clever you have
  238.      * to be careful when you reset the firstByte so that the server only
  239.      * notices after it has caught up with everything at the end of the
  240.      * buffer.  To keep things simple we just wait for the server to catch up
  241.      * completely if we can't fit this request in.)
  242.      */
  243.  
  244.     savedFirstByte = firstByte;
  245.     savedLastByte = lastByte;
  246.     if (firstByte > lastByte || firstByte == -1) {
  247.     /*
  248.      * Buffer has emptied.
  249.      */
  250.     firstByte = 0;
  251.     pdevHandlePtr->requestBuf.firstByte = firstByte;
  252.     lastByte = requestHdrPtr->messageSize - 1;
  253.     } else {
  254.     room = pdevHandlePtr->requestBuf.size - (lastByte + 1);
  255.     if (room < requestHdrPtr->messageSize) {
  256.         /*
  257.          * There is no room left at the end of the buffer.
  258.          * We wait and then put the request at the beginning.
  259.          */
  260.         while (pdevHandlePtr->requestBuf.firstByte <
  261.            pdevHandlePtr->requestBuf.lastByte) {
  262.         DBG_PRINT( (" (catch up) ") );
  263.         if (Sync_Wait(&pdevHandlePtr->caughtUp, TRUE)) {
  264.             status = GEN_ABORTED_BY_SIGNAL;
  265.             goto failure;
  266.         } else if (pdevHandlePtr->flags & PDEV_SERVER_GONE) {
  267.             status = DEV_OFFLINE;
  268.             goto failure;
  269.         }
  270.         }
  271.         savedFirstByte = -1;
  272.         firstByte = 0;
  273.         pdevHandlePtr->requestBuf.firstByte = firstByte;
  274.         lastByte = requestHdrPtr->messageSize - 1;
  275.     } else {
  276.         /*
  277.          * Append the message to the other requests.
  278.          */
  279.         firstByte = lastByte + 1;
  280.         lastByte += requestHdrPtr->messageSize;
  281.     }
  282.     }
  283.     pdevHandlePtr->requestBuf.lastByte = lastByte;
  284.     DBG_PRINT( (" first %d last %d\n", firstByte, lastByte) );
  285.     pdevHandlePtr->operation = requestHdrPtr->operation;
  286.     if (pdevHandlePtr->operation == PFS_OPEN) {
  287.     /*
  288.      * We have to snarf up the hostID of the client doing the open
  289.      * so the new pseudo-device connection that may be set up as
  290.      * a side effect of PFS_OPEN is set up right.  The useFlags are
  291.      * needed to initialize the new client stream right.
  292.      */
  293.     register Pfs_Request *pfsRequestPtr = (Pfs_Request *)requestHdrPtr;
  294.     pdevHandlePtr->open.clientID = pfsRequestPtr->param.open.clientID;
  295.     pdevHandlePtr->open.useFlags = pfsRequestPtr->param.open.useFlags;
  296.     pdevHandlePtr->open.name = (char *)inputBuf;
  297.     }
  298.  
  299.     /*
  300.      * COPY REQUEST AND DATA.
  301.      * Copy the request and data out into the server's request buffer.
  302.      * We map to a proc table pointer for the server which has a side
  303.      * effect of locking down the server process so it can't disappear.
  304.      */
  305.  
  306.     serverProcPtr = Proc_LockPID(pdevHandlePtr->serverPID);
  307.     if (serverProcPtr == (Proc_ControlBlock *)NIL) {
  308.     status = DEV_OFFLINE;
  309.     goto failure;
  310.     }
  311.     status = Vm_CopyOutProc(hdrSize, (Address)requestHdrPtr, TRUE,
  312.                 serverProcPtr, (Address)
  313.                 &pdevHandlePtr->requestBuf.data[firstByte]);
  314.     if (status == SUCCESS) {
  315.     firstByte += hdrSize;
  316.     if (inputSize > 0) {
  317.         status = Vm_CopyOutProc(inputSize, inputBuf, 
  318.             (pdevHandlePtr->flags & FS_USER_IN) == 0, serverProcPtr,
  319.             (Address)&pdevHandlePtr->requestBuf.data[firstByte]);
  320.     }
  321.     }
  322.     Proc_Unlock(serverProcPtr);
  323.     if (status != SUCCESS) {
  324.     /*
  325.      * Either the message header or data couldn't get copied out.
  326.      * Reset the buffer pointers so the bad request isn't seen.
  327.      */
  328.     pdevHandlePtr->requestBuf.firstByte = savedFirstByte;
  329.     pdevHandlePtr->requestBuf.lastByte = savedLastByte;
  330.     goto failure;
  331.     }
  332.  
  333.     /*
  334.      * POKE THE SERVER so it can read the new pointer values.
  335.      * This is done here even if write-behind is enabled, even though our
  336.      * scheduler tends to wake up the server too soon.
  337.      * Although it is possible to put a notify in about 3 other places
  338.      * to catch cases where the client does a write-behind and then waits,
  339.      * not all clients are clever enough to use select.  That solution results
  340.      * in cases where a write can linger a long time in the request buffer.
  341.      * (cat /dev/syslog in a tx window is a good test case.)
  342.      */
  343.     Fsutil_FastWaitListNotify(&pdevHandlePtr->srvReadWaitList);
  344.  
  345.     if (pdevHandlePtr->operation != PDEV_WRITE_ASYNC) {
  346.     /*
  347.      * WAIT FOR A REPLY.
  348.      * We save the client's reply buffer address and processID in the
  349.      * stream state so the kernel can copy the reply directly from
  350.      * the server's address space to the client's when the server
  351.      * makes the IOC_PDEV_REPLY IOControl.
  352.      */
  353.  
  354.     pdevHandlePtr->replyBuf = replyBuf;
  355.     pdevHandlePtr->replySize = replySize;
  356.     pdevHandlePtr->clientPID = (Proc_GetEffectiveProc())->processID;
  357.     if (waitPtr != (Sync_RemoteWaiter *)NIL) {
  358.         pdevHandlePtr->clientWait = *waitPtr;
  359.     }
  360.     pdevHandlePtr->flags &= ~PDEV_REPLY_READY;
  361.     while ((pdevHandlePtr->flags & PDEV_REPLY_READY) == 0) {
  362.         if (Sync_Wait(&pdevHandlePtr->replyReady, TRUE)) {
  363.         if ((pdevHandlePtr->flags & PDEV_REPLY_READY) == 0) {
  364.             /*
  365.              * Client aborted before the server completed the request.
  366.              */
  367.             pdevHandlePtr->flags |= PDEV_REQUEST_ABORTED;
  368.         }
  369.         status = GEN_ABORTED_BY_SIGNAL;
  370.         goto failure;
  371.         } else if (pdevHandlePtr->flags &
  372.             (PDEV_REPLY_FAILED|PDEV_SERVER_GONE)) {
  373.         status = DEV_OFFLINE;
  374.         goto failure;
  375.         }
  376.     }
  377.     if (ioReplyPtr != (Fs_IOReply *) NIL) {
  378.         ioReplyPtr->length = pdevHandlePtr->reply.replySize;
  379.         ioReplyPtr->signal = pdevHandlePtr->reply.signal;
  380.         ioReplyPtr->code = pdevHandlePtr->reply.code;
  381.     }
  382.     } else {
  383.     pdevHandlePtr->reply.status = SUCCESS;
  384.     }
  385. failure:
  386.     pdevHandlePtr->replyBuf = (char *)NIL;
  387.     pdevHandlePtr->replySize = 0;
  388.     if (status == SUCCESS) {
  389.     status = pdevHandlePtr->reply.status;
  390.     }
  391.     return(status);
  392. }
  393.  
  394. /*
  395.  *----------------------------------------------------------------------
  396.  *
  397.  * FspdevServerStreamCreate --
  398.  *
  399.  *    Set up the stream state for a server's private channel to a client.
  400.  *    This creates a Fspdev_ServerIOHandle that has all the state for the
  401.  *    connection to the client.
  402.  *
  403.  * Results:
  404.  *    A pointer to the I/O handle created.  The handle is locked.
  405.  *    NIL is returned if a handle under the fileID already existed.
  406.  *
  407.  * Side effects:
  408.  *    The I/O handle for this connection between a client and the server
  409.  *    is installed and initialized.
  410.  *
  411.  *----------------------------------------------------------------------
  412.  */
  413.  
  414. Fspdev_ServerIOHandle *
  415. FspdevServerStreamCreate(ioFileIDPtr, name, naming)
  416.     Fs_FileID    *ioFileIDPtr;    /* File ID used for pseudo stream handle */
  417.     char    *name;        /* File name for error messages */
  418.     Boolean    naming;        /* True if this is a naming stream for a pfs */
  419. {
  420.     Fs_HandleHeader *hdrPtr;
  421.     register Fspdev_ServerIOHandle *pdevHandlePtr;
  422.     Boolean found;
  423.  
  424.     ioFileIDPtr->type = FSIO_SERVER_STREAM;
  425.     found = Fsutil_HandleInstall(ioFileIDPtr, sizeof(Fspdev_ServerIOHandle), name,
  426.                 FALSE, &hdrPtr);
  427.     pdevHandlePtr = (Fspdev_ServerIOHandle *)hdrPtr;
  428.     if (found) {
  429.     printf("ServerStreamCreate, found handle <%x,%x,%x>\n",
  430.           hdrPtr->fileID.serverID, hdrPtr->fileID.major,
  431.           hdrPtr->fileID.minor);
  432.     Fsutil_HandleRelease(pdevHandlePtr, TRUE);
  433.     return((Fspdev_ServerIOHandle *)NIL);
  434.     }
  435.     fs_Stats.object.pseudoStreams++;
  436.  
  437.     DBG_PRINT( ("ServerStreamOpen <%d,%x,%x>\n",
  438.         ioFileIDPtr->serverID, ioFileIDPtr->major, ioFileIDPtr->minor) );
  439.  
  440.     /*
  441.      * Initialize the state for the pseudo stream.  Remember that
  442.      * the request and read ahead buffers for the pseudo-stream are set up
  443.      * via IOControls by the server process later.  In the meantime we
  444.      * pretend the connection is busy to lock out requests.
  445.      */
  446.  
  447.     Sync_LockInitDynamic(&pdevHandlePtr->lock, "Fs:pdevLock");
  448.     pdevHandlePtr->flags = PDEV_BUSY;
  449.     if (naming) {
  450.     pdevHandlePtr->flags |= PDEV_NAMING;
  451.     }
  452.     pdevHandlePtr->selectBits = 0;
  453.     pdevHandlePtr->serverPID = (Proc_PID)NIL;
  454.     pdevHandlePtr->clientPID = (Proc_PID)NIL;
  455.  
  456.     pdevHandlePtr->requestBuf.data = (Address)NIL;
  457.     pdevHandlePtr->requestBuf.firstByte = -1;
  458.     pdevHandlePtr->requestBuf.lastByte = -1;
  459.     pdevHandlePtr->requestBuf.size = 0;
  460.  
  461.     pdevHandlePtr->nextRequestBuffer = (Address)NIL;
  462.  
  463.     pdevHandlePtr->readBuf.data = (Address)NIL;
  464.     pdevHandlePtr->readBuf.firstByte = -1;
  465.     pdevHandlePtr->readBuf.lastByte = -1;
  466.     pdevHandlePtr->readBuf.size = 0;
  467.  
  468.     pdevHandlePtr->operation = 0;
  469.     pdevHandlePtr->reply.status = NIL;
  470.     pdevHandlePtr->reply.replySize = 0;
  471.     pdevHandlePtr->replyBuf = (Address)NIL;
  472.  
  473.     pdevHandlePtr->setup.waiting = 0;
  474.     pdevHandlePtr->access.waiting = 0;
  475.     pdevHandlePtr->caughtUp.waiting = 0;
  476.     pdevHandlePtr->replyReady.waiting = 0;
  477.  
  478.     List_Init(&pdevHandlePtr->srvReadWaitList);
  479.  
  480.     pdevHandlePtr->clientWait.pid = NIL;
  481.     pdevHandlePtr->clientWait.hostID = NIL;
  482.     pdevHandlePtr->clientWait.waitToken = NIL;
  483.  
  484.     List_Init(&pdevHandlePtr->cltReadWaitList);
  485.     List_Init(&pdevHandlePtr->cltWriteWaitList);
  486.     List_Init(&pdevHandlePtr->cltExceptWaitList);
  487.  
  488.     pdevHandlePtr->ctrlHandlePtr = (Fspdev_ControlIOHandle *)NIL;
  489.  
  490.     pdevHandlePtr->userLevelID = *ioFileIDPtr;
  491.     pdevHandlePtr->open.clientID = NIL;
  492.     pdevHandlePtr->open.useFlags = 0;
  493.     pdevHandlePtr->open.name = (char *)NIL;
  494.  
  495.     return(pdevHandlePtr);
  496. }
  497.  
  498. /*
  499.  *----------------------------------------------------------------------
  500.  *
  501.  * FspdevServerStreamSelect --
  502.  *
  503.  *    Select a server's request/response stream.  This returns
  504.  *    FS_READABLE in the outFlags if there is data in the
  505.  *    server's request buffer.  The next read on the server stream
  506.  *    will return the current pointers into the buffer.
  507.  *
  508.  * Results:
  509.  *    SUCCESS
  510.  *
  511.  * Side effects:
  512.  *    None.
  513.  *
  514.  *----------------------------------------------------------------------
  515.  */
  516.  
  517. ReturnStatus
  518. FspdevServerStreamSelect(hdrPtr, waitPtr, readPtr, writePtr, exceptPtr)
  519.     Fs_HandleHeader    *hdrPtr;    /* Handle on device to select */
  520.     Sync_RemoteWaiter    *waitPtr;    /* Process info for remote waiting */
  521.     int         *readPtr;    /* Bit to clear if non-readable */
  522.     int         *writePtr;    /* Bit to clear if non-writeable */
  523.     int         *exceptPtr;    /* Bit to clear if non-exceptable */
  524. {
  525.     register Fspdev_ServerIOHandle    *pdevHandlePtr = (Fspdev_ServerIOHandle *)hdrPtr;
  526.  
  527.     LOCK_MONITOR;
  528.     if (*readPtr) {
  529.     if (((pdevHandlePtr->flags & PDEV_READ_PTRS_CHANGED) == 0) &&
  530.          ((pdevHandlePtr->requestBuf.firstByte == -1) ||
  531.           (pdevHandlePtr->requestBuf.firstByte >=
  532.           pdevHandlePtr->requestBuf.lastByte))) {
  533.         *readPtr = 0;
  534.         if (waitPtr != (Sync_RemoteWaiter *)NIL) {
  535.         Fsutil_FastWaitListInsert(&pdevHandlePtr->srvReadWaitList, waitPtr);
  536.         }
  537.     }
  538.     }
  539.     *writePtr = 0;
  540.     *exceptPtr = 0;
  541.     UNLOCK_MONITOR;
  542.     return(SUCCESS);
  543. }
  544.  
  545. /*
  546.  *----------------------------------------------------------------------
  547.  *
  548.  * FspdevServerStreamRead --
  549.  *
  550.  *    When the server reads on a server stream it is looking for a
  551.  *    message containing pointers into the request buffer that's
  552.  *    in its address spapce.  This routine returns those values.
  553.  *
  554.  * Results:
  555.  *    SUCCESS unless all clients have gone away.
  556.  *
  557.  * Side effects:
  558.  *    The buffer is filled a Pdev_BufPtrs structure.
  559.  *
  560.  *----------------------------------------------------------------------
  561.  */
  562. /*ARGSUSED*/
  563. ReturnStatus
  564. FspdevServerStreamRead(streamPtr, readPtr, waitPtr, replyPtr)
  565.     register Fs_Stream     *streamPtr;    /* Stream to read from. */
  566.     Fs_IOParam        *readPtr;    /* Read parameter block. */
  567.     Sync_RemoteWaiter    *waitPtr;    /* Process info for remote waiting */
  568.     Fs_IOReply        *replyPtr;    /* Signal to return, if any,
  569.                      * plus the amount read. */
  570. {
  571.     register Fspdev_ServerIOHandle *pdevHandlePtr =
  572.         (Fspdev_ServerIOHandle *)streamPtr->ioHandlePtr;
  573.     register ReturnStatus status;
  574.     Pdev_BufPtrs bufPtrs;
  575.     register int reqFirstByte, reqLastByte;
  576.  
  577.     LOCK_MONITOR;
  578.     /*
  579.      * The server stream is readable only if there are requests in the
  580.      * request buffer or if the read ahead buffers have changed since
  581.      * the last time the server did a read.
  582.      */
  583.     reqFirstByte = pdevHandlePtr->requestBuf.firstByte;
  584.     reqLastByte = pdevHandlePtr->requestBuf.lastByte;
  585.     if (reqFirstByte > pdevHandlePtr->requestBuf.size ||
  586.     reqLastByte > pdevHandlePtr->requestBuf.size) {
  587.     panic("PdevServerRead, pointers inconsistent\n");
  588.     UNLOCK_MONITOR;
  589.     return(GEN_INVALID_ARG);
  590.     }
  591.     if (((pdevHandlePtr->flags & PDEV_READ_PTRS_CHANGED) == 0) &&
  592.     ((reqFirstByte == -1) || (reqFirstByte > reqLastByte))) {
  593.     status = FS_WOULD_BLOCK;
  594.     replyPtr->length = 0;
  595.     Fsutil_FastWaitListInsert(&pdevHandlePtr->srvReadWaitList, waitPtr);
  596.     PDEV_TRACE(&pdevHandlePtr->hdr.fileID, PDEVT_SRV_READ_WAIT);
  597.     } else {
  598.     /*
  599.      * Copy the current pointers out to the server.  We include the
  600.      * server's address of the request buffer to support changing
  601.      * the request buffer after requests have started to flow.
  602.      */
  603.     PDEV_TRACE(&pdevHandlePtr->hdr.fileID, PDEVT_SRV_READ);
  604.     bufPtrs.magic = PDEV_BUF_PTR_MAGIC;
  605.     bufPtrs.requestAddr = pdevHandlePtr->requestBuf.data;
  606.     if ((reqFirstByte == -1) || (reqFirstByte > reqLastByte)) {
  607.         /*
  608.          * Request buffer is empty.
  609.          */
  610.         bufPtrs.requestFirstByte = -1;
  611.         bufPtrs.requestLastByte = -1;
  612.     } else {
  613.         bufPtrs.requestFirstByte = reqFirstByte;
  614.         bufPtrs.requestLastByte = reqLastByte;
  615.     }
  616.  
  617.     /*
  618.      * The read ahead buffer is filled by the server until there is
  619.      * no room left.  Only after the kernel has emptied the
  620.      * read ahead buffer will the server start filling it again.
  621.      * We use the PDEV_SERVER_KNOWS_IT state bit to know when to
  622.      * expect new pointer values after the buffer empties.
  623.      */
  624.     if (pdevHandlePtr->flags & PDEV_READ_BUF_EMPTY) {
  625.         bufPtrs.readLastByte = -1;
  626.         bufPtrs.readFirstByte = -1;
  627.         pdevHandlePtr->flags |= PDEV_SERVER_KNOWS_IT;
  628.     } else {
  629.         bufPtrs.readFirstByte = pdevHandlePtr->readBuf.firstByte;
  630.         bufPtrs.readLastByte = pdevHandlePtr->readBuf.lastByte;
  631.     }
  632.     pdevHandlePtr->flags &= ~PDEV_READ_PTRS_CHANGED;
  633.     status = Vm_CopyOut(sizeof(Pdev_BufPtrs), (Address)&bufPtrs,
  634.                 readPtr->buffer);
  635.     replyPtr->length = sizeof(Pdev_BufPtrs);
  636.     DBG_PRINT( ("READ %x,%x req %d:%d read %d:%d\n",
  637.         pdevHandlePtr->hdr.fileID.major,
  638.         pdevHandlePtr->hdr.fileID.minor,
  639.         pdevHandlePtr->requestBuf.firstByte,
  640.         pdevHandlePtr->requestBuf.lastByte,
  641.         pdevHandlePtr->readBuf.firstByte,
  642.         pdevHandlePtr->readBuf.lastByte) );
  643.     }
  644.     UNLOCK_MONITOR;
  645.     return(status);
  646. }
  647.  
  648. /*
  649.  *----------------------------------------------------------------------
  650.  *
  651.  * FspdevServerStreamIOControl --
  652.  *
  653.  *    IOControls for the server's stream.  The server process uses this
  654.  *    to manipulate the request and read ahead buffers in its address
  655.  *    space.  It delcares them, and queries and sets pointers into them.
  656.  *    The server also replies to requests here, and notifies the kernel
  657.  *    when the pseudo-device is selectable.
  658.  *
  659.  * Results:
  660.  *    SUCCESS if all went well, otherwise a status from a Vm operation
  661.  *    or a consistency check.
  662.  *
  663.  * Side effects:
  664.  *    This is the main entry point for the server process to control
  665.  *    the pseudo-device connection to its clients.  The side effects
  666.  *    depend on the I/O control.
  667.  *
  668.  *----------------------------------------------------------------------
  669.  */
  670. /*ARGSUSED*/
  671. ENTRY ReturnStatus
  672. FspdevServerStreamIOControl(streamPtr, ioctlPtr, replyPtr)
  673.     Fs_Stream    *streamPtr;    /* Stream to server handle. */
  674.     Fs_IOCParam *ioctlPtr;    /* Standard I/O Control parameter block */
  675.     Fs_IOReply *replyPtr;    /* Output buffer length and signal to return */
  676. {
  677.     ReturnStatus    status = SUCCESS;
  678.     register Fspdev_ServerIOHandle    *pdevHandlePtr =
  679.         (Fspdev_ServerIOHandle *)streamPtr->ioHandlePtr;
  680.  
  681.     LOCK_MONITOR;
  682.  
  683.     if (ioctlPtr->format != mach_Format) {
  684.     panic("FsServerStreamIOControl: wrong format\n");
  685.     }
  686.     switch (ioctlPtr->command) {
  687.     case IOC_PDEV_SET_BUF: {
  688.         /*
  689.          * The server is declaring the buffer space used for requests
  690.          * and (optionally) for read ahead.
  691.          * To support UDP socket semantics, we let the server change
  692.          * the request buffer after things have already started up.
  693.          * (This is sort of a pain, as we have to let the current
  694.          * request buffer empty before switching.)
  695.          *
  696.          * Side effects:
  697.          *        Set the request, and optionally the read-ahead,
  698.          *        buffer pointers.  The setup condition is notified
  699.          *        to let the client's open transaction begin.
  700.          */
  701.         register Pdev_SetBufArgs *argPtr =
  702.             (Pdev_SetBufArgs *)ioctlPtr->inBuffer;
  703.         register int extraBytes;
  704.  
  705.         if (ioctlPtr->inBufSize != sizeof(Pdev_SetBufArgs)) {
  706.         status = GEN_INVALID_ARG;
  707.         } else if ((pdevHandlePtr->flags & PDEV_SETUP) == 0) {
  708.         /*
  709.          * Normal case, first time initialization.  Make sure the
  710.          * buffers are word aligned.
  711.          */
  712.         pdevHandlePtr->requestBuf.size = argPtr->requestBufSize;
  713.         pdevHandlePtr->requestBuf.data = argPtr->requestBufAddr;
  714.         extraBytes = (unsigned int)argPtr->requestBufAddr &
  715.                  (sizeof(int) - 1);
  716.         if (extraBytes) {
  717.             pdevHandlePtr->requestBuf.data += sizeof(int) - extraBytes;
  718.             pdevHandlePtr->requestBuf.size -= extraBytes;
  719.         }
  720.         pdevHandlePtr->requestBuf.firstByte = -1;
  721.         pdevHandlePtr->requestBuf.lastByte = -1;
  722.  
  723.         if (argPtr->readBufAddr == (Address)NIL ||
  724.             argPtr->readBufAddr == (Address)0) {
  725.             pdevHandlePtr->readBuf.data = (Address)NIL;
  726.             pdevHandlePtr->readBuf.size = 0;
  727.         } else {
  728.             pdevHandlePtr->readBuf.size = argPtr->readBufSize;
  729.             pdevHandlePtr->readBuf.data = argPtr->readBufAddr;
  730.             extraBytes = (unsigned int)argPtr->readBufAddr &
  731.                  (sizeof(int) - 1);
  732.             if (extraBytes) {
  733.             pdevHandlePtr->readBuf.data += sizeof(int) - extraBytes;
  734.             pdevHandlePtr->readBuf.size -= extraBytes;
  735.             }
  736.         }
  737.         pdevHandlePtr->readBuf.firstByte = -1;
  738.         pdevHandlePtr->readBuf.lastByte = -1;
  739.  
  740.         pdevHandlePtr->serverPID = ioctlPtr->procID;
  741.  
  742.         /*
  743.          * The state has been marked BUSY to simplify waiting in the
  744.          * routines that call RequestResponse, so we clear that bit.
  745.          */
  746.         pdevHandlePtr->flags &= ~PDEV_BUSY;
  747.         pdevHandlePtr->flags |= PDEV_SETUP|PDEV_READ_BUF_EMPTY|
  748.                          PDEV_SERVER_KNOWS_IT;
  749.         Sync_Broadcast(&pdevHandlePtr->access);
  750.         } else {
  751.         /*
  752.          * The server is changing request buffers.  We just remember
  753.          * the new buffer address and size here, and switch over
  754.          * in RequestResponse after the current request buffer empties.
  755.          */
  756.         pdevHandlePtr->nextRequestBuffer = argPtr->requestBufAddr;
  757.         pdevHandlePtr->nextRequestBufSize = argPtr->requestBufSize;
  758.         if (pdevHandlePtr->nextRequestBuffer == (Address)0) {
  759.             pdevHandlePtr->nextRequestBuffer = (Address)NIL;
  760.         }
  761.         }
  762.         break;
  763.     }
  764.     case IOC_PDEV_WRITE_BEHIND: {
  765.         /*
  766.          * Side effects:
  767.          *        Set/unset write-behind buffering in the request buffer.
  768.          */
  769.         register Boolean writeBehind;
  770.         if (ioctlPtr->inBufSize < sizeof(Boolean)) {
  771.         status = GEN_INVALID_ARG;
  772.         } else {
  773.         writeBehind = *(Boolean *)ioctlPtr->inBuffer;
  774.         if (writeBehind) {
  775.             pdevHandlePtr->flags |= PDEV_WRITE_BEHIND;
  776.         } else {
  777.             pdevHandlePtr->flags &= ~PDEV_WRITE_BEHIND;
  778.         }
  779.         }
  780.         break;
  781.     }
  782.     case IOC_PDEV_BIG_WRITES: {
  783.         /*
  784.          * Side effects:
  785.          *        Set/unset the client's ability to make large writes.
  786.          */
  787.         register Boolean allowLargeWrites;
  788.         if (ioctlPtr->inBufSize < sizeof(Boolean)) {
  789.         status = GEN_INVALID_ARG;
  790.         } else {
  791.         allowLargeWrites = *(Boolean *)ioctlPtr->inBuffer;
  792.         if (allowLargeWrites) {
  793.             pdevHandlePtr->flags &= ~PDEV_NO_BIG_WRITES;
  794.         } else {
  795.             pdevHandlePtr->flags |= PDEV_NO_BIG_WRITES;
  796.         }
  797.         }
  798.         break;
  799.     }
  800.     case IOC_PDEV_SET_PTRS: {
  801.         /*
  802.          * The server is telling us about new pointer values.  We only
  803.          * pay attention to the requestFirstByte and readLastByte as
  804.          * it is our job to modify the other pointers.
  805.          *
  806.          * Side effects:
  807.          *        Set requestBuf.firstByte and readBuf.lastByte if
  808.          *        the server gives us new values (not equal -1).
  809.          *        We notify waiting clients if the server has
  810.          *        added read-ahead data.
  811.          */
  812.         register Pdev_BufPtrs *argPtr = (Pdev_BufPtrs *)ioctlPtr->inBuffer;
  813.         if (ioctlPtr->inBufSize != sizeof(Pdev_BufPtrs)) {
  814.         status = GEN_INVALID_ARG;
  815.         } else {
  816.         /*
  817.          * Verify the request buffer pointer.  The server may just
  818.          * be telling us about read ahead data, in which case we
  819.          * shouldn't muck with the request pointers. Otherwise we
  820.          * update the request first byte to reflect the processing
  821.          * of some requests by the server.
  822.          */
  823.         DBG_PRINT( ("SET  %x,%x req %d:%d read %d:%d\n",
  824.             pdevHandlePtr->hdr.fileID.major,
  825.             pdevHandlePtr->hdr.fileID.minor,
  826.             argPtr->requestFirstByte, argPtr->requestLastByte,
  827.             argPtr->readFirstByte, argPtr->readLastByte) );
  828.         if (argPtr->requestFirstByte <=
  829.                     pdevHandlePtr->requestBuf.size &&
  830.             argPtr->requestFirstByte >= 0) {
  831.             pdevHandlePtr->requestBuf.firstByte =
  832.                argPtr->requestFirstByte;
  833.         }
  834.         Sync_Broadcast(&pdevHandlePtr->caughtUp);
  835.             if ((pdevHandlePtr->readBuf.data == (Address)NIL) ||
  836.             (argPtr->readLastByte < 0)) {
  837.             /*
  838.              * No read ahead info.
  839.              */
  840.             break;
  841.         }
  842.         if (argPtr->readLastByte > pdevHandlePtr->readBuf.size) {
  843.             printf("FspdevServerStreamIOControl: set bad readPtr\n");
  844.             status = GEN_INVALID_ARG;
  845.             break;
  846.         }
  847.         if ((pdevHandlePtr->flags & PDEV_READ_BUF_EMPTY) == 0) {
  848.             /*
  849.              * Non-empty buffer.  Break out if bad pointer, else
  850.              * fall through to code that updates the pointer.
  851.              */
  852.             if (argPtr->readLastByte <=
  853.             pdevHandlePtr->readBuf.lastByte) {
  854.                 break;    /* No new read ahead data */
  855.             }
  856.         } else if (pdevHandlePtr->flags & PDEV_SERVER_KNOWS_IT) {
  857.             /*
  858.              * Empty buffer and the server already knows this.
  859.              * We can safely reset firstByte to the beginning.
  860.              * The server should rely on this behavior.
  861.              */
  862.             if (argPtr->readLastByte >= 0) {
  863.             pdevHandlePtr->flags &= ~(PDEV_READ_BUF_EMPTY|
  864.                          PDEV_SERVER_KNOWS_IT);
  865.             pdevHandlePtr->readBuf.firstByte = 0;
  866.             } else {
  867.             break;    /* No new read ahead data */
  868.             }
  869.         } else {
  870.             /*
  871.              * We emptied the buffer, but the server added data
  872.              * before seeing it was empty.  Can't reset firstByte.
  873.              */
  874.             if (argPtr->readLastByte > 
  875.                 pdevHandlePtr->readBuf.lastByte) {
  876.             pdevHandlePtr->flags &= ~PDEV_READ_BUF_EMPTY;
  877.             } else {
  878.             break;    /* No new read ahead data */
  879.             }
  880.         }
  881.         /*
  882.          * We know here that the lastByte pointer indicates
  883.          * more data.  Otherwise we've broken out.
  884.          * Update select state and poke waiting readers.
  885.          */
  886.         pdevHandlePtr->readBuf.lastByte = argPtr->readLastByte;
  887.         pdevHandlePtr->selectBits |= FS_READABLE;
  888.         Fsutil_FastWaitListNotify(&pdevHandlePtr->cltReadWaitList);
  889.         }
  890.         break;
  891.     }
  892.     case IOC_PDEV_SMALL_REPLY:
  893.     case IOC_PDEV_REPLY: {
  894.         /*
  895.          * The server is replying to a request.
  896.          *
  897.          * Side effects:
  898.          *        Copy the reply from the server to the client.
  899.          *        Put the client on wait lists, if appropriate.
  900.          *        Notify the replyReady condition, and lastly
  901.          *        notify waiting clients about new select state.
  902.          */
  903.         register Pdev_Reply *srvReplyPtr = (Pdev_Reply *)ioctlPtr->inBuffer;
  904.  
  905.         if (ioctlPtr->inBufSize < sizeof(Pdev_Reply)) {
  906.         /*
  907.          * inBuffer must be at least as big as Pdev_Reply.
  908.          * It will be larger during PDEV_SMALL_REPLY which
  909.          * includes a small amount of embedded data.
  910.          */
  911.         status = FS_INVALID_ARG;
  912.         pdevHandlePtr->flags |= PDEV_REPLY_READY|PDEV_REPLY_FAILED;
  913.         } else if (pdevHandlePtr->flags & PDEV_REQUEST_ABORTED) {
  914.         /*
  915.          * Client aborted the request from its end.
  916.          * Do nothing but grab the select bits.
  917.          */
  918.         pdevHandlePtr->flags &= ~PDEV_REQUEST_ABORTED;
  919.         pdevHandlePtr->selectBits = srvReplyPtr->selectBits;
  920.         } else {
  921.         /*
  922.          * Copy current reply in to pdev state.
  923.          */
  924.         pdevHandlePtr->reply = *srvReplyPtr;
  925.         if (srvReplyPtr->replySize > 0) {
  926.             register Proc_ControlBlock *clientProcPtr;
  927.             if (pdevHandlePtr->replyBuf == (char *)NIL) {
  928.             printf("PdevReply: unwanted reply data <%s>\n",
  929.                 Fsutil_HandleName(pdevHandlePtr));
  930.             goto noReplyData;
  931.             }
  932.             if (srvReplyPtr->replySize > pdevHandlePtr->replySize) {
  933.             printf("PdevReply: extra reply data (%d > %d) <%s>\n",
  934.                 srvReplyPtr->replySize, pdevHandlePtr->replySize,
  935.                 Fsutil_HandleName(pdevHandlePtr));
  936.             srvReplyPtr->replySize = pdevHandlePtr->replySize;
  937.             }
  938.             /*
  939.              * Copy the reply into the waiting buffers.
  940.              */
  941.             if ((ioctlPtr->command == IOC_PDEV_SMALL_REPLY) &&
  942.             ((srvReplyPtr->replySize > PDEV_SMALL_DATA_LIMIT) ||
  943.              (ioctlPtr->inBufSize <
  944.                  sizeof(Pdev_Reply) + srvReplyPtr->replySize))){
  945.             status = GEN_INVALID_ARG;
  946.             } else {
  947.             if ((pdevHandlePtr->flags & FS_USER_OUT) == 0) {
  948.                 /*
  949.                  * Reply buffer in the kernel.
  950.                  */
  951.                 if (ioctlPtr->command == IOC_PDEV_SMALL_REPLY) {
  952.                 bcopy(((Pdev_ReplyData *)srvReplyPtr)->data,
  953.                     pdevHandlePtr->replyBuf,
  954.                     srvReplyPtr->replySize);
  955.                 } else {
  956.                 status = Vm_CopyIn(srvReplyPtr->replySize,
  957.                            srvReplyPtr->replyBuf,
  958.                            pdevHandlePtr->replyBuf);
  959.                 }
  960.             } else {
  961.                 clientProcPtr = Proc_LockPID(pdevHandlePtr->clientPID);
  962.                 /*
  963.                  * Reply buffer in the client's address space.
  964.                  * Do a cross-address-space copy.
  965.                  */
  966.                 if (clientProcPtr == (Proc_ControlBlock *)NIL) {
  967.                 status = FS_BROKEN_PIPE;
  968.                 } else {
  969.                 if (ioctlPtr->command == IOC_PDEV_SMALL_REPLY) {
  970.                     status =
  971.                     Vm_CopyOutProc(srvReplyPtr->replySize,
  972.                     ((Pdev_ReplyData *)srvReplyPtr)->data,
  973.                     TRUE, clientProcPtr,
  974.                     pdevHandlePtr->replyBuf);
  975.                 } else {
  976.                     status =
  977.                     Vm_CopyOutProc(srvReplyPtr->replySize,
  978.                     srvReplyPtr->replyBuf, FALSE,
  979.                     clientProcPtr, pdevHandlePtr->replyBuf);
  980.                 }
  981.                 Proc_Unlock(clientProcPtr);
  982.                 }
  983.             }
  984.             }
  985.             if (status != SUCCESS) {
  986.             pdevHandlePtr->flags |= PDEV_REPLY_FAILED;
  987.             }
  988.         }
  989. noReplyData:
  990.         PDEV_REPLY(&pdevHandlePtr->hdr.fileID, srvReplyPtr);
  991.         if (srvReplyPtr->status == FS_WOULD_BLOCK) {
  992.             /*
  993.              * Put the client process on the appropriate wait list.
  994.              */
  995.             if (pdevHandlePtr->operation == PDEV_READ) {
  996.             Fsutil_FastWaitListInsert(&pdevHandlePtr->cltReadWaitList,
  997.                          &pdevHandlePtr->clientWait);
  998.             } else if (pdevHandlePtr->operation == PDEV_WRITE) {
  999.             Fsutil_FastWaitListInsert(&pdevHandlePtr->cltWriteWaitList,
  1000.                          &pdevHandlePtr->clientWait);
  1001.             }
  1002.         }
  1003.         pdevHandlePtr->flags |= PDEV_REPLY_READY;
  1004.         pdevHandlePtr->selectBits = srvReplyPtr->selectBits;
  1005.         }
  1006.         Sync_Broadcast(&pdevHandlePtr->replyReady);
  1007.         PdevClientNotify(pdevHandlePtr);
  1008.         break;
  1009.     }
  1010.     case IOC_PDEV_READY:
  1011.         /*
  1012.          * Master has made the device ready.  The inBuffer contains
  1013.          * new select bits.
  1014.          *
  1015.          * Side effects:
  1016.          *        Notify waiting clients.
  1017.          */
  1018.  
  1019.         if (ioctlPtr->inBufSize != sizeof(int)) {
  1020.         status = FS_INVALID_ARG;
  1021.         } else {
  1022.         /*
  1023.          * Update the select state of the pseudo-device and
  1024.          * wake up any clients waiting on their pseudo-stream.
  1025.          */
  1026.         pdevHandlePtr->selectBits = *(int *)ioctlPtr->inBuffer;
  1027.         PdevClientNotify(pdevHandlePtr);
  1028.         }
  1029.         break;
  1030.     case IOC_PDEV_SIGNAL_OWNER: {
  1031.         /*
  1032.          * The server wants to signal the process (group) that owns
  1033.          * the device.  This is used, for example, to implement processing
  1034.          * of interrupt characters by the TTY driver.
  1035.          */
  1036.         status = FspdevSignalOwner(pdevHandlePtr->ctrlHandlePtr, ioctlPtr);
  1037.         break;
  1038.     }
  1039.     case IOC_PFS_OPEN: {
  1040.         /*
  1041.          * A pseudo-filesystem server is replying to an open request by
  1042.          * asking us to open a pseudo-device connection to the client.
  1043.          * It gives us a Fs_FileID for its own identification of the
  1044.          * connection.  The connection is set up here. A user-level
  1045.          * streamID is generated for the server process and returned.
  1046.          * To finish up, we set up the Fs_OpenResults that the waiting
  1047.          * client has to RequestResponse.  This includes a fileID so
  1048.          * the client process can fetch its half of the connection.
  1049.          */
  1050.         int newStreamID;            /* For the server */
  1051.         Fs_OpenResults openResults;        /* For the client */
  1052.  
  1053.         if (ioctlPtr->inBufSize < sizeof(Fs_FileID) ||
  1054.         ioctlPtr->outBufSize < sizeof(int)) {
  1055.         status = GEN_INVALID_ARG;
  1056.         } else if (pdevHandlePtr->flags & PDEV_REQUEST_ABORTED) {
  1057.         pdevHandlePtr->flags &= ~PDEV_REQUEST_ABORTED;
  1058.         PdevClientNotify(pdevHandlePtr);
  1059.         break;
  1060.         } else {
  1061.         newStreamID = FspdevPfsOpenConnection(pdevHandlePtr,
  1062.                 (Fs_FileID *)ioctlPtr->inBuffer, &openResults);
  1063.         if (ioctlPtr->flags & FS_USER_OUT) {
  1064.             Vm_CopyOut(sizeof(int), (Address)&newStreamID,
  1065.                 ioctlPtr->outBuffer);
  1066.         } else {
  1067.             *(int *)ioctlPtr->outBuffer = newStreamID;
  1068.         }
  1069.         if (newStreamID < 0) {
  1070.             status = FAILURE;
  1071.         } else {
  1072.             /*
  1073.              * Here we copy the openResults to the waiting processes
  1074.              * kernel stack (it's waiting in FspdevPfsOpen on this
  1075.              * same host.)
  1076.              */
  1077.             register Fs_OpenResults *openResultsPtr =
  1078.                 (Fs_OpenResults *)pdevHandlePtr->replyBuf;
  1079.             *openResultsPtr = openResults;
  1080.         }
  1081.         }
  1082.         if (status != SUCCESS) {
  1083.         pdevHandlePtr->flags |= PDEV_REPLY_FAILED;
  1084.         pdevHandlePtr->reply.replySize = 0;
  1085.         } else {
  1086.         pdevHandlePtr->reply.replySize = sizeof(Fs_OpenResults);
  1087.         }
  1088.         pdevHandlePtr->reply.status = status;
  1089.         pdevHandlePtr->flags |= PDEV_REPLY_READY;
  1090.         Sync_Broadcast(&pdevHandlePtr->replyReady);
  1091.         PdevClientNotify(pdevHandlePtr);
  1092.         break;
  1093.     }
  1094.     case IOC_PFS_SET_ID: {
  1095.         /*
  1096.          * A pseudo-filesystem server is setting its own notion of the
  1097.          * fileID associated with a request-response stream.
  1098.          */
  1099.         register Fs_FileID *fileIDPtr;
  1100.  
  1101.         if (ioctlPtr->inBufSize < sizeof(Fs_FileID)) {
  1102.         status = FS_INVALID_ARG;
  1103.         } else {
  1104.         fileIDPtr = (Fs_FileID *)ioctlPtr->inBuffer;
  1105.         pdevHandlePtr->userLevelID = *fileIDPtr;
  1106.         }
  1107.         break;
  1108.     }
  1109.     case IOC_PFS_PASS_STREAM: {
  1110.         /*
  1111.          * A pseudo-filesystem server is replying to an open request by
  1112.          * asking us to pass one of its open streams to the client.
  1113.          */
  1114.         register int passedStreamID;    /* From the server */
  1115.         Fs_OpenResults openResults;        /* For the client */
  1116.         Address encapStream;        /* packaged stream */
  1117.         int encapSize;            /* size of package */
  1118.         register Proc_ControlBlock *procPtr;
  1119.         register Fs_OpenResults *openResultsPtr;
  1120.  
  1121.         if (ioctlPtr->inBufSize < sizeof(int)) {
  1122.         status = GEN_INVALID_ARG;
  1123.         } else if (pdevHandlePtr->flags & PDEV_REQUEST_ABORTED) {
  1124.         pdevHandlePtr->flags &= ~PDEV_REQUEST_ABORTED;
  1125.         PdevClientNotify(pdevHandlePtr);
  1126.         break;
  1127.         } else {
  1128.         passedStreamID = *(int *)ioctlPtr->inBuffer;
  1129.         procPtr = Proc_GetEffectiveProc();
  1130.         status = Fs_GetStreamPtr(procPtr, passedStreamID, &streamPtr);
  1131.         if (status == SUCCESS) {
  1132.             encapSize = Fs_GetEncapSize();
  1133.             encapStream = (Address)malloc(encapSize);
  1134.             status = Fsio_EncapStream(streamPtr, encapStream);
  1135.             if (status == SUCCESS) {
  1136.             /*
  1137.              * Set up open results so Fs_Open will call a cltOpen
  1138.              * routine that will unpackage the encapsulated stream.
  1139.              */
  1140.             bzero((char *)&openResults, sizeof(Fs_OpenResults));
  1141.             openResults.ioFileID.type = FSIO_PASSING_STREAM;
  1142.             openResults.dataSize = encapSize;
  1143.             openResults.streamData = (ClientData)encapStream;
  1144.  
  1145.             openResultsPtr =
  1146.                 (Fs_OpenResults *)pdevHandlePtr->replyBuf;
  1147.             *openResultsPtr = openResults;
  1148.             }
  1149.         }
  1150.         }
  1151.         if (status != SUCCESS) {
  1152.         pdevHandlePtr->flags |= PDEV_REPLY_FAILED;
  1153.         pdevHandlePtr->reply.replySize = 0;
  1154.         } else {
  1155.         pdevHandlePtr->reply.replySize = sizeof(Fs_OpenResults);
  1156.         }
  1157.         pdevHandlePtr->reply.status = status;
  1158.         pdevHandlePtr->flags |= PDEV_REPLY_READY;
  1159.         Sync_Broadcast(&pdevHandlePtr->replyReady);
  1160.         PdevClientNotify(pdevHandlePtr);
  1161.         break;
  1162.     }
  1163.     case IOC_REPOSITION:
  1164.         status = GEN_INVALID_ARG;
  1165.         break;
  1166.     case IOC_GET_FLAGS:
  1167.     case IOC_SET_FLAGS:
  1168.     case IOC_SET_BITS:
  1169.     case IOC_CLEAR_BITS:
  1170.         /*
  1171.          * There are no server stream specific flags.
  1172.          */
  1173.         break;
  1174.     case IOC_TRUNCATE:
  1175.     case IOC_LOCK:
  1176.     case IOC_UNLOCK:
  1177.     case IOC_MAP:
  1178.         status = FS_INVALID_ARG;
  1179.         break;
  1180.     case IOC_GET_OWNER:
  1181.     case IOC_SET_OWNER:
  1182.         status = GEN_NOT_IMPLEMENTED;
  1183.         break;
  1184.     case IOC_NUM_READABLE: {
  1185.         /*
  1186.          * The server stream is readable only if there are requests in the
  1187.          * request buffer or if the read ahead buffers have changed since
  1188.          * the last time the server did a read.
  1189.          *
  1190.          * Side effects:
  1191.          *        None.
  1192.          */
  1193.         register int reqFirstByte, reqLastByte;
  1194.         register int numReadable;
  1195.  
  1196.         reqFirstByte = pdevHandlePtr->requestBuf.firstByte;
  1197.         reqLastByte = pdevHandlePtr->requestBuf.lastByte;
  1198.         if (((pdevHandlePtr->flags & PDEV_READ_PTRS_CHANGED) == 0) &&
  1199.         ((reqFirstByte == -1) || (reqFirstByte > reqLastByte))) {
  1200.         numReadable = 0;
  1201.         } else {
  1202.         numReadable = sizeof(Pdev_BufPtrs);
  1203.         }
  1204.         if (ioctlPtr->outBuffer == (Address)NIL ||
  1205.         ioctlPtr->outBufSize < sizeof(int)) {
  1206.         status = GEN_INVALID_ARG;
  1207.         } else {
  1208.         *(int *)ioctlPtr->outBuffer = numReadable;
  1209.         status = SUCCESS;
  1210.         }
  1211.         break;
  1212.     }
  1213.     case IOC_PREFIX: 
  1214.         status = SUCCESS;
  1215.         break;
  1216.     default:
  1217.         status = GEN_NOT_IMPLEMENTED;
  1218.         break;
  1219.     }
  1220.     UNLOCK_MONITOR;
  1221.     return(status);
  1222. }
  1223.  
  1224. /*
  1225.  *----------------------------------------------------------------------
  1226.  *
  1227.  * FspdevSignalOwner --
  1228.  *
  1229.  *    Send a signal to the owning process or family of a pseudo-device.
  1230.  *
  1231.  * Results:
  1232.  *    FS_INVALID_ARG if the input buffer isn't right.
  1233.  *
  1234.  * Side effects:
  1235.  *    Bypasses permissions and sends the signal.  Permissions have to
  1236.  *    be bypassed otherwise the pseudo-device server has to be setuid.
  1237.  *
  1238.  *----------------------------------------------------------------------
  1239.  */
  1240.  
  1241. ReturnStatus
  1242. FspdevSignalOwner(ctrlHandlePtr, ioctlPtr)
  1243.     Fspdev_ControlIOHandle *ctrlHandlePtr;
  1244.     Fs_IOCParam *ioctlPtr;
  1245. {
  1246.     register ReturnStatus status;
  1247.     register Pdev_Signal *sigPtr;
  1248.     register Ioc_Owner *ownerPtr = &ctrlHandlePtr->owner;
  1249.     register Proc_ControlBlock *procPtr;
  1250.  
  1251.     if (ownerPtr->procOrFamily == 0) {
  1252.     /*
  1253.      * No owner declared, this is a no-op.
  1254.      */
  1255.     status = SUCCESS;
  1256.     } else if (ioctlPtr->inBufSize != sizeof(Pdev_Signal)) {
  1257.     status = FS_INVALID_ARG;
  1258.     } else {
  1259.     register int savedEuid;
  1260.  
  1261.     sigPtr = (Pdev_Signal *)ioctlPtr->inBuffer;
  1262.     procPtr = Proc_GetEffectiveProc();
  1263.     savedEuid = procPtr->effectiveUserID;
  1264.     procPtr->effectiveUserID = 0;
  1265.     status = Sig_Send(sigPtr->signal, sigPtr->code, ownerPtr->id,
  1266.          (ownerPtr->procOrFamily == IOC_OWNER_FAMILY), (Address)0);
  1267.     procPtr->effectiveUserID = savedEuid;
  1268.     }
  1269.     return(status);
  1270. }
  1271.  
  1272.  
  1273. /*
  1274.  *----------------------------------------------------------------------
  1275.  *
  1276.  * FspdevServerStreamClose --
  1277.  *
  1278.  *    Clean up the state associated with a server stream.  This makes
  1279.  *    sure the client processes associated with the pseudo stream get
  1280.  *    poked, and it marks the pseudo stream's state as invalid so
  1281.  *    the clients will abort their current operations, if any.  The
  1282.  *    handle is 'removed' here, but it won't go away until the client
  1283.  *    side closes down and releases its reference to it.
  1284.  *
  1285.  * Results:
  1286.  *    SUCCESS.
  1287.  *
  1288.  * Side effects:
  1289.  *    Marks the pseudo stream state with PDEV_SERVER_GONE, notifies
  1290.  *    all conditions in pseudo stream state, wakes up all processes
  1291.  *    in any of the pseudo stream's wait lists, and then removes
  1292.  *    the handle from the hash table.
  1293.  *
  1294.  *----------------------------------------------------------------------
  1295.  */
  1296. /*ARGSUSED*/
  1297. #ifdef SOSP91
  1298. ReturnStatus
  1299. FspdevServerStreamClose(streamPtr, clientID, procID, flags, size, data, 
  1300.     offsetPtr, rwFlagsPtr)
  1301. #else
  1302. ReturnStatus
  1303. FspdevServerStreamClose(streamPtr, clientID, procID, flags, size, data)
  1304. #endif
  1305.     Fs_Stream        *streamPtr;    /* Service stream to close */
  1306.     int            clientID;    /* HostID of client closing */
  1307.     Proc_PID        procID;        /* ID of closing process */
  1308.     int            flags;        /* Flags from the stream being closed */
  1309.     int            size;        /* Should be zero */
  1310.     ClientData        data;        /* IGNORED */
  1311. #ifdef SOSP91
  1312.     int            *offsetPtr;
  1313.     int            *rwFlagsPtr;
  1314. #endif
  1315. {
  1316.     register Fspdev_ServerIOHandle *pdevHandlePtr =
  1317.         (Fspdev_ServerIOHandle *)streamPtr->ioHandlePtr;
  1318.  
  1319.     DBG_PRINT( ("Server Closing pdev %x,%x\n", 
  1320.         pdevHandlePtr->hdr.fileID.major,
  1321.         pdevHandlePtr->hdr.fileID.minor) );
  1322.  
  1323.     PdevClientWakeup(pdevHandlePtr);
  1324.     if (pdevHandlePtr->flags & PDEV_NAMING) {
  1325.     /*
  1326.      * Clean up the prefix table entry associated with the pfs.
  1327.      */
  1328.     register Fspdev_ControlIOHandle *ctrlHandlePtr;
  1329.     Fs_Stream dummy;
  1330.  
  1331.     ctrlHandlePtr = pdevHandlePtr->ctrlHandlePtr;
  1332.     dummy.hdr.fileID.type = -1;
  1333.     dummy.ioHandlePtr = (Fs_HandleHeader *)ctrlHandlePtr;
  1334.     Fsutil_HandleLock(ctrlHandlePtr);
  1335.     Fsprefix_HandleClose(ctrlHandlePtr->prefixPtr, FSPREFIX_ANY);
  1336. #ifdef SOSP91
  1337.     (void)FspdevControlClose(&dummy, clientID, procID, flags, 0, 
  1338.         (ClientData)NIL, (int *) NIL, (int *) NIL);
  1339. #else
  1340.     (void)FspdevControlClose(&dummy, clientID, procID, flags, 0, (ClientData)NIL);
  1341. #endif
  1342.     }
  1343.     Sync_LockClear(&pdevHandlePtr->lock);
  1344.     Fsutil_HandleRelease(pdevHandlePtr, TRUE);
  1345.     Fsutil_HandleRemove(pdevHandlePtr);    /* No need for scavenging */
  1346.     fs_Stats.object.pseudoStreams--;
  1347.     return(SUCCESS);
  1348. }
  1349.  
  1350. /*
  1351.  *----------------------------------------------------------------------
  1352.  *
  1353.  * PdevClientWakeup --
  1354.  *
  1355.  *    Called when the server's stream is closed.  This
  1356.  *    notifies the various conditions that the client might be
  1357.  *    waiting on and marks the pdev state as invalid so the
  1358.  *    client will bail out when it wakes up.
  1359.  *
  1360.  * Results:
  1361.  *    None.
  1362.  *
  1363.  * Side effects:
  1364.  *    Notifies condition variables and marks the pseudo stream as invalid.
  1365.  *
  1366.  *----------------------------------------------------------------------
  1367.  */
  1368.  
  1369. ENTRY static void
  1370. PdevClientWakeup(pdevHandlePtr)
  1371.     Fspdev_ServerIOHandle *pdevHandlePtr;    /* State for the pseudo stream */
  1372. {
  1373.     LOCK_MONITOR;
  1374.     /*
  1375.      * Set both "busy" and "server gone" because the standard preamble
  1376.      * for all client routines only checks against "server gone"
  1377.      * inside a while-not-busy loop.
  1378.      */
  1379.     pdevHandlePtr->flags |= (PDEV_SERVER_GONE|PDEV_REPLY_FAILED|PDEV_BUSY);
  1380.     Sync_Broadcast(&pdevHandlePtr->access);
  1381.     Sync_Broadcast(&pdevHandlePtr->caughtUp);
  1382.     Sync_Broadcast(&pdevHandlePtr->replyReady);
  1383.     Fsutil_FastWaitListNotify(&pdevHandlePtr->cltReadWaitList);
  1384.     Fsutil_FastWaitListNotify(&pdevHandlePtr->cltWriteWaitList);
  1385.     Fsutil_FastWaitListNotify(&pdevHandlePtr->cltExceptWaitList);
  1386.     Fsutil_WaitListDelete(&pdevHandlePtr->cltReadWaitList);
  1387.     Fsutil_WaitListDelete(&pdevHandlePtr->cltWriteWaitList);
  1388.     Fsutil_WaitListDelete(&pdevHandlePtr->cltExceptWaitList);
  1389.     Fsutil_WaitListDelete(&pdevHandlePtr->srvReadWaitList);
  1390.     UNLOCK_MONITOR;
  1391. }
  1392.  
  1393. /*
  1394.  *----------------------------------------------------------------------
  1395.  *
  1396.  * FspdevPdevServerOK --
  1397.  *
  1398.  *    Called from FspdevPfsExport to see if the server of a prefix still exists.
  1399.  *
  1400.  * Results:
  1401.  *    TRUE if the server process is still around.
  1402.  *
  1403.  * Side effects:
  1404.  *    None.
  1405.  *
  1406.  *----------------------------------------------------------------------
  1407.  */
  1408.  
  1409. ENTRY Boolean
  1410. FspdevPdevServerOK(pdevHandlePtr)
  1411.     Fspdev_ServerIOHandle *pdevHandlePtr;    /* State for the pseudo stream */
  1412. {
  1413.     register Boolean answer;
  1414.     LOCK_MONITOR;
  1415.     if (pdevHandlePtr->flags & PDEV_SERVER_GONE) {
  1416.     answer = FALSE;
  1417.     } else {
  1418.     answer = TRUE;
  1419.     }
  1420.     UNLOCK_MONITOR;
  1421.     return(answer);
  1422. }
  1423.  
  1424.  
  1425. /*
  1426.  *----------------------------------------------------------------------
  1427.  *
  1428.  * FspdevPseudoStreamOpen --
  1429.  *
  1430.  *    Do the first request-response with a pseudo-device server to see if it
  1431.  *    will accept the open by the client.   This is used to tell
  1432.  *    the server something about the new stream it is getting,
  1433.  *    and to let it decide if it will accept the open.
  1434.  *
  1435.  * Results:
  1436.  *    The return status from the server's reply.  It can reject the open.
  1437.  *
  1438.  * Side effects:
  1439.  *    An PDEV_OPEN request-response is carried out.
  1440.  *
  1441.  *----------------------------------------------------------------------
  1442.  */
  1443.  
  1444. ENTRY ReturnStatus
  1445. FspdevPseudoStreamOpen(pdevHandlePtr, flags, clientID, procID, userID)
  1446.     register Fspdev_ServerIOHandle *pdevHandlePtr;    /* Pdev connection state */
  1447.     int        flags;        /* Open flags */
  1448.     int        clientID;    /* Host ID of the client */
  1449.     Proc_PID    procID;        /* Process ID of the client process */
  1450.     int        userID;        /* User ID of the client process */
  1451. {
  1452.     register ReturnStatus     status;
  1453.     Pdev_Request        request;
  1454.  
  1455.     LOCK_MONITOR;
  1456.  
  1457.     /*
  1458.      * Wait for the server to set up the request buffer.  The state starts
  1459.      * out PDEV_BUSY to eliminate an explicit check for PDEV_SETUP in all
  1460.      * the routines that call RequestResponse.  PDEV_BUSY is cleared after
  1461.      * the server initializes the request buffer with IOC_PDEV_SETUP.
  1462.      */
  1463.     while (pdevHandlePtr->flags & PDEV_BUSY) { 
  1464.     if ((pdevHandlePtr->flags & PDEV_SERVER_GONE) == 0) {
  1465.         (void)Sync_Wait(&pdevHandlePtr->access, FALSE);
  1466.     }
  1467.     if (pdevHandlePtr->flags & PDEV_SERVER_GONE) {
  1468.         status = DEV_OFFLINE;
  1469.         goto exit;
  1470.     }
  1471.     }
  1472.     pdevHandlePtr->flags |= PDEV_BUSY;
  1473.  
  1474.     /*
  1475.      * Issue the first request to the server to see if it will accept us.
  1476.      */
  1477.  
  1478.     request.hdr.operation    = PDEV_OPEN;
  1479.     request.param.open.flags    = flags;
  1480.     request.param.open.pid    = procID;
  1481.     request.param.open.hostID    = clientID;
  1482.     request.param.open.uid    = userID;
  1483.  
  1484.     pdevHandlePtr->flags &= ~(FS_USER_IN|FS_USER_OUT);
  1485.     status = RequestResponse(pdevHandlePtr, sizeof(Pdev_Request), &request.hdr,
  1486.              0, (Address) NIL, 0, (Address) NIL, (Fs_IOReply *)NIL,
  1487.              (Sync_RemoteWaiter *)NIL);
  1488.     pdevHandlePtr->flags &= ~PDEV_BUSY;
  1489. exit:
  1490.     Sync_Broadcast(&pdevHandlePtr->access);
  1491.     UNLOCK_MONITOR;
  1492.     return(status);
  1493. }
  1494.  
  1495. /*
  1496.  *----------------------------------------------------------------------
  1497.  *
  1498.  * FspdevPseudoStreamLookup --
  1499.  *
  1500.  *    Do a lookup request-response to a pseudo-filesystem server over
  1501.  *    the naming request-response stream that is hooked to the prefix table.
  1502.  *    If a pathname redirection occurs this allocates a buffer for the
  1503.  *    returned pathname.  Otherwise this is a stub that passes its arguments
  1504.  *    up to the user level pseudo-filesystem server via request-response.
  1505.  *
  1506.  * Results:
  1507.  *    A status and some bundled results that aren't interpreted by us.
  1508.  *    If status is FS_REDIRECT then *newNameInfoPtrPtr has been allocated
  1509.  *    and contains the returned pathname.
  1510.  *
  1511.  * Side effects:
  1512.  *    The effect of the naming operation in the pseudo-filesystem is
  1513.  *    up to the pseudo-filesystem server.  Upon FS_REDIRECT this
  1514.  *    allocates the *newNameInfoPtrPtr buffer.
  1515.  *
  1516.  *----------------------------------------------------------------------
  1517.  */
  1518.  
  1519. ENTRY ReturnStatus
  1520. FspdevPseudoStreamLookup(pdevHandlePtr, requestPtr, argSize, argsPtr,
  1521.             resultsSizePtr, resultsPtr, newNameInfoPtrPtr)
  1522.     register Fspdev_ServerIOHandle *pdevHandlePtr;    /* Pdev connection state */
  1523.     Pfs_Request        *requestPtr;    /* Semi-initialized request header */
  1524.     int            argSize;    /* Size of argsPtr buffer */
  1525.     Address        argsPtr;    /* Ref. to bundled args, usually name */
  1526.     int            *resultsSizePtr;/* Out size of results */
  1527.     Address        resultsPtr;    /* Ref. to bundled results or 
  1528.                      * Fs_RedirectInfo */
  1529.     Fs_RedirectInfo    **newNameInfoPtrPtr;/* Set if server returns name */
  1530. {
  1531.     register ReturnStatus     status;
  1532.     Fs_RedirectInfo        redirectInfo;    /* This is a large buffer
  1533.                          * that is used for EITHER
  1534.                          * normal reply parameters
  1535.                          * or a redirected pathname */
  1536.     Fs_IOReply            ioReply;
  1537.  
  1538.     LOCK_MONITOR;
  1539.  
  1540.     *newNameInfoPtrPtr = (Fs_RedirectInfo *)NIL;
  1541.  
  1542.     while (pdevHandlePtr->flags & PDEV_BUSY) {
  1543.     if ((pdevHandlePtr->flags & PDEV_SERVER_GONE) == 0) {
  1544.         (void)Sync_Wait(&pdevHandlePtr->access, FALSE);
  1545.     }
  1546.     if (pdevHandlePtr->flags & PDEV_SERVER_GONE) {
  1547.         status = FS_STALE_HANDLE;
  1548.         goto exit;
  1549.     }
  1550.     }
  1551.     pdevHandlePtr->flags |= PDEV_BUSY;
  1552.  
  1553.     pdevHandlePtr->flags &= ~(FS_USER_IN|FS_USER_OUT);
  1554.     status = RequestResponse(pdevHandlePtr, sizeof(Pfs_Request),
  1555.         &requestPtr->hdr, argSize, argsPtr, sizeof(Fs_RedirectInfo),
  1556.         (Address)&redirectInfo, &ioReply,
  1557.         (Sync_RemoteWaiter *)NIL);
  1558.     if (status == FS_LOOKUP_REDIRECT) {
  1559.     *newNameInfoPtrPtr = mnew(Fs_RedirectInfo);
  1560.     (*newNameInfoPtrPtr)->prefixLength = redirectInfo.prefixLength;
  1561.     (void)strcpy((*newNameInfoPtrPtr)->fileName, redirectInfo.fileName);
  1562.     } else {
  1563.     /*
  1564.      * Grab the result parameters.
  1565.      */
  1566.     *resultsSizePtr = ioReply.length;
  1567.     if (ioReply.length > 0) {
  1568.         bcopy((Address)&redirectInfo, resultsPtr, ioReply.length);
  1569.     }
  1570.     }
  1571.  
  1572.     if (status == DEV_OFFLINE) {
  1573.     /*
  1574.      * Return stale handle so remote clients know to nuke
  1575.      * their prefix table entry.
  1576.      */
  1577.     status = FS_STALE_HANDLE;
  1578.     }
  1579.     pdevHandlePtr->flags &= ~PDEV_BUSY;
  1580. exit:
  1581.     Sync_Broadcast(&pdevHandlePtr->access);
  1582.     UNLOCK_MONITOR;
  1583.     return(status);
  1584. }
  1585.  
  1586. /*
  1587.  *----------------------------------------------------------------------
  1588.  *
  1589.  * FspdevPseudoStream2Path --
  1590.  *
  1591.  *    Do a rename/link request-response to a pseudo-filesystem server over
  1592.  *    the naming request-response stream that is hooked to the prefix table.
  1593.  *    If a pathname redirection occurs this allocates a buffer for the
  1594.  *    returned pathname.  Otherwise this is a stub that passes its arguments
  1595.  *    up to the user level pseudo-filesystem server via request-response.
  1596.  *
  1597.  * Results:
  1598.  *    A status and some bundled results that aren't interpreted by us.
  1599.  *    If status is FS_REDIRECT then *newNameInfoPtrPtr has been allocated
  1600.  *    and contains the returned pathname.
  1601.  *
  1602.  * Side effects:
  1603.  *    The effect of the naming operation in the pseudo-filesystem is
  1604.  *    up to the pseudo-filesystem server.  Upon FS_REDIRECT this
  1605.  *    allocates the *newNameInfoPtrPtr buffer.
  1606.  *
  1607.  *----------------------------------------------------------------------
  1608.  */
  1609.  
  1610. ENTRY ReturnStatus
  1611. FspdevPseudoStream2Path(pdevHandlePtr, requestPtr, dataPtr, name1ErrorPtr,
  1612.             newNameInfoPtrPtr)
  1613.     register Fspdev_ServerIOHandle *pdevHandlePtr;    /* Pdev connection state */
  1614.     Pfs_Request        *requestPtr;    /* Semi-initialized request header */
  1615.     Fs_2PathData        *dataPtr;    /* 2 pathnames */
  1616.     Boolean        *name1ErrorPtr;    /* TRUE if error applies to first path*/
  1617.     Fs_RedirectInfo    **newNameInfoPtrPtr;/* Set if server returns name */
  1618. {
  1619.     register ReturnStatus     status;
  1620.     Fs_2PathRedirectInfo        redirectInfo;
  1621.  
  1622.     LOCK_MONITOR;
  1623.  
  1624.     while (pdevHandlePtr->flags & PDEV_BUSY) {
  1625.     if ((pdevHandlePtr->flags & PDEV_SERVER_GONE) == 0) {
  1626.         (void)Sync_Wait(&pdevHandlePtr->access, FALSE);
  1627.     }
  1628.     if (pdevHandlePtr->flags & PDEV_SERVER_GONE) {
  1629.         status = FS_STALE_HANDLE;
  1630.         goto exit;
  1631.     }
  1632.     }
  1633.     pdevHandlePtr->flags |= PDEV_BUSY;
  1634.  
  1635.     pdevHandlePtr->flags &= ~(FS_USER_IN|FS_USER_OUT);
  1636.     status = RequestResponse(pdevHandlePtr, sizeof(Pfs_Request),
  1637.         &requestPtr->hdr, sizeof(Fs_2PathData), (Address)dataPtr,
  1638.         sizeof(Fs_2PathRedirectInfo), (Address)&redirectInfo,
  1639.         (Fs_IOReply *)NIL, (Sync_RemoteWaiter *)NIL);
  1640.     if (status == FS_LOOKUP_REDIRECT) {
  1641.     *newNameInfoPtrPtr = mnew(Fs_RedirectInfo);
  1642.     (*newNameInfoPtrPtr)->prefixLength = redirectInfo.prefixLength;
  1643.     (void)strcpy((*newNameInfoPtrPtr)->fileName, redirectInfo.fileName);
  1644.     }
  1645.     if (status != SUCCESS) {
  1646.     *name1ErrorPtr = redirectInfo.name1ErrorP;
  1647.     } else {
  1648.     *name1ErrorPtr = FALSE;
  1649.     }
  1650.  
  1651.     if (status == DEV_OFFLINE) {
  1652.     /*
  1653.      * Return stale handle so remote clients know to nuke
  1654.      * their prefix table entry.
  1655.      */
  1656.     status = FS_STALE_HANDLE;
  1657.     }
  1658.     pdevHandlePtr->flags &= ~PDEV_BUSY;
  1659. exit:
  1660.     Sync_Broadcast(&pdevHandlePtr->access);
  1661.     UNLOCK_MONITOR;
  1662.     return(status);
  1663. }
  1664.  
  1665. /*
  1666.  *----------------------------------------------------------------------
  1667.  *
  1668.  * FspdevPseudoGetAttr --
  1669.  *
  1670.  *    Called from Fs_GetAttributesID to get the attributes of a file
  1671.  *    in a pseudo-filesystem.  The stream's nameInfoPtr->fileID is
  1672.  *    set to the fileID of the pseudo-device connection to the server,
  1673.  *    and this ID is passed into us.  This does a PDEV_GET_ATTR request.
  1674.  *
  1675.  * Results:
  1676.  *    The attributes structure is passed back from the pfs server.
  1677.  *
  1678.  * Side effects:
  1679.  *    None.
  1680.  *
  1681.  *----------------------------------------------------------------------
  1682.  */
  1683. /*ARGSUSED*/
  1684. ReturnStatus
  1685. FspdevPseudoGetAttr(fileIDPtr, clientID, attrPtr)
  1686.     register Fs_FileID        *fileIDPtr;    /* Identfies pdev connection */
  1687.     int                clientID;    /* Host ID of process asking
  1688.                          * for the attributes */
  1689.     register Fs_Attributes    *attrPtr;    /* Return - the attributes */
  1690. {
  1691.     Fspdev_ClientIOHandle        *cltHandlePtr;
  1692.     Pdev_Request        request;
  1693.     register Fspdev_ServerIOHandle    *pdevHandlePtr;
  1694.     register ReturnStatus    status;
  1695.  
  1696.     cltHandlePtr = Fsutil_HandleFetchType(Fspdev_ClientIOHandle, fileIDPtr);
  1697.     if (cltHandlePtr == (Fspdev_ClientIOHandle *)NIL) {
  1698.     printf( "FspdevPseudoGetAttr, no %s handle <%d,%x,%x>\n",
  1699.         Fsutil_FileTypeToString(fileIDPtr->type), fileIDPtr->serverID,
  1700.         fileIDPtr->major, fileIDPtr->minor);
  1701.     return(FS_FILE_NOT_FOUND);
  1702.     }
  1703.     Fsutil_HandleRelease(cltHandlePtr, TRUE);
  1704.     pdevHandlePtr = cltHandlePtr->pdevHandlePtr;
  1705.     LOCK_MONITOR;
  1706.  
  1707.     while (pdevHandlePtr->flags & PDEV_BUSY) {
  1708.     if ((pdevHandlePtr->flags & PDEV_SERVER_GONE) == 0) {
  1709.         (void)Sync_Wait(&pdevHandlePtr->access, FALSE);
  1710.     }
  1711.     if (pdevHandlePtr->flags & PDEV_SERVER_GONE) {
  1712.         status = DEV_OFFLINE;
  1713.         goto exit;
  1714.     }
  1715.     }
  1716.     pdevHandlePtr->flags |= PDEV_BUSY;
  1717.     pdevHandlePtr->flags &= ~(FS_USER_IN|FS_USER_OUT);
  1718.     request.hdr.operation = PDEV_GET_ATTR;
  1719.     status = RequestResponse(pdevHandlePtr, sizeof(Pdev_Request), &request.hdr,
  1720.             0, (Address) NIL,
  1721.             sizeof(Fs_Attributes), (Address)attrPtr,
  1722.             (Fs_IOReply *)NIL, (Sync_RemoteWaiter *)NIL);
  1723.     /*
  1724.      * Patch the serverID in the attributes so it matches the serverID
  1725.      * given in the prefix table.  This is needed to make getwd() work.
  1726.      */
  1727.     attrPtr->serverID = rpc_SpriteID;
  1728.  
  1729.     pdevHandlePtr->flags &= ~PDEV_BUSY;
  1730. exit:
  1731.     Sync_Broadcast(&pdevHandlePtr->access);
  1732.     UNLOCK_MONITOR;
  1733.     return(status);
  1734. }
  1735.  
  1736. /*
  1737.  *----------------------------------------------------------------------
  1738.  *
  1739.  * FspdevPseudoSetAttr --
  1740.  *
  1741.  *    Set the attributes of a file in a pseudo-filesystem.  We have the
  1742.  *    fileID of the request-response stream to the server.  This issues
  1743.  *    a PDEV_SET_ATTR request to the server that contains new attributes.
  1744.  *
  1745.  * Results:
  1746.  *    An error code.
  1747.  *
  1748.  * Side effects:
  1749.  *    None here.  The new attributes are shipped to the pfs server.
  1750.  *
  1751.  *----------------------------------------------------------------------
  1752.  */
  1753. /*ARGSUSED*/
  1754. ReturnStatus
  1755. FspdevPseudoSetAttr(fileIDPtr, attrPtr, idPtr, flags)
  1756.     register Fs_FileID        *fileIDPtr;    /* Identfies pdev connection */
  1757.     register Fs_Attributes    *attrPtr;    /* Return - the attributes */
  1758.     Fs_UserIDs            *idPtr;        /* Identfies user */
  1759.     int                flags;        /* Tells which attrs to set */
  1760. {
  1761.     Fspdev_ClientIOHandle        *cltHandlePtr;
  1762.     Pdev_Request        request;
  1763.     register Fspdev_ServerIOHandle    *pdevHandlePtr;
  1764.     register ReturnStatus    status;
  1765.  
  1766.     cltHandlePtr = Fsutil_HandleFetchType(Fspdev_ClientIOHandle, fileIDPtr);
  1767.     if (cltHandlePtr == (Fspdev_ClientIOHandle *)NIL) {
  1768.     printf( "FspdevPseudoSetAttr, no handle <%d,%d,%x,%x>\n",
  1769.         fileIDPtr->serverID, fileIDPtr->type,
  1770.         fileIDPtr->major, fileIDPtr->minor);
  1771.     return(FS_FILE_NOT_FOUND);
  1772.     }
  1773.     Fsutil_HandleRelease(cltHandlePtr, TRUE);
  1774.     pdevHandlePtr = cltHandlePtr->pdevHandlePtr;
  1775.     LOCK_MONITOR;
  1776.  
  1777.     while (pdevHandlePtr->flags & PDEV_BUSY) {
  1778.     if ((pdevHandlePtr->flags & PDEV_SERVER_GONE) == 0) {
  1779.         (void)Sync_Wait(&pdevHandlePtr->access, FALSE);
  1780.     }
  1781.     if (pdevHandlePtr->flags & PDEV_SERVER_GONE) {
  1782.         status = DEV_OFFLINE;
  1783.         goto exit;
  1784.     }
  1785.     }
  1786.     pdevHandlePtr->flags |= PDEV_BUSY;
  1787.     pdevHandlePtr->flags &= ~(FS_USER_IN|FS_USER_OUT);
  1788.     request.hdr.operation = PDEV_SET_ATTR;
  1789.     request.param.setAttr.uid = idPtr->user;
  1790.     request.param.setAttr.flags = flags;
  1791.     status = RequestResponse(pdevHandlePtr, sizeof(Pdev_Request), &request.hdr,
  1792.             sizeof(Fs_Attributes), (Address)attrPtr,
  1793.             0, (Address) NIL,
  1794.             (Fs_IOReply *)NIL, (Sync_RemoteWaiter *)NIL);
  1795.     pdevHandlePtr->flags &= ~PDEV_BUSY;
  1796. exit:
  1797.     Sync_Broadcast(&pdevHandlePtr->access);
  1798.     UNLOCK_MONITOR;
  1799.     return(status);
  1800. }
  1801.  
  1802. /*
  1803.  *----------------------------------------------------------------------
  1804.  *
  1805.  * FspdevPseudoStreamGetIOAttr --
  1806.  *
  1807.  *    Called from Fs_GetAttrStream to get the I/O attributes of a
  1808.  *    pseudo-device.  The access and modify times of the pseudo-device
  1809.  *    are obtained from the internal pdev state.
  1810.  *
  1811.  * Results:
  1812.  *    SUCCESS.
  1813.  *
  1814.  * Side effects:
  1815.  *    None.
  1816.  *
  1817.  *----------------------------------------------------------------------
  1818.  */
  1819. ReturnStatus
  1820. FspdevPseudoStreamGetIOAttr(fileIDPtr, clientID, attrPtr)
  1821.     register Fs_FileID        *fileIDPtr;    /* Identfies pdev connection */
  1822.     int                clientID;    /* Host ID of process asking
  1823.                          * for the attributes */
  1824.     register Fs_Attributes    *attrPtr;    /* Return - the attributes */
  1825. {
  1826.     Fspdev_ClientIOHandle        *cltHandlePtr;
  1827.     register Fspdev_ServerIOHandle    *pdevHandlePtr;
  1828.  
  1829.     cltHandlePtr = Fsutil_HandleFetchType(Fspdev_ClientIOHandle, fileIDPtr);
  1830.     if (cltHandlePtr == (Fspdev_ClientIOHandle *)NIL) {
  1831.     printf( "FspdevPseudoStreamGetIOAttr, no %s handle <%d,%x,%x> client %d\n",
  1832.         Fsutil_FileTypeToString(fileIDPtr->type), fileIDPtr->serverID,
  1833.         fileIDPtr->major, fileIDPtr->minor, clientID);
  1834.     return(FS_FILE_NOT_FOUND);
  1835.     }
  1836.     Fsutil_HandleRelease(cltHandlePtr, TRUE);
  1837.     pdevHandlePtr = cltHandlePtr->pdevHandlePtr;
  1838.     LOCK_MONITOR;
  1839.  
  1840.     attrPtr->accessTime.seconds = pdevHandlePtr->ctrlHandlePtr->accessTime;
  1841.     attrPtr->dataModifyTime.seconds = pdevHandlePtr->ctrlHandlePtr->modifyTime;
  1842.  
  1843.     UNLOCK_MONITOR;
  1844.     return(SUCCESS);
  1845. }
  1846.  
  1847. /*
  1848.  *----------------------------------------------------------------------
  1849.  *
  1850.  * FspdevPseudoStreamSetIOAttr --
  1851.  *
  1852.  *    Set the IO attributes of a pseudo-device.
  1853.  *
  1854.  * Results:
  1855.  *    An error code.
  1856.  *
  1857.  * Side effects:
  1858.  *    Updates the access and modify times kept in the pdev state.
  1859.  *
  1860.  *----------------------------------------------------------------------
  1861.  */
  1862. ReturnStatus
  1863. FspdevPseudoStreamSetIOAttr(fileIDPtr, attrPtr, flags)
  1864.     register Fs_FileID        *fileIDPtr;    /* Identfies pdev connection */
  1865.     register Fs_Attributes    *attrPtr;    /* Return - the attributes */
  1866.     int                flags;        /* Tells which attrs to set */
  1867. {
  1868.     Fspdev_ClientIOHandle        *cltHandlePtr;
  1869.     register Fspdev_ServerIOHandle    *pdevHandlePtr;
  1870.  
  1871.     cltHandlePtr = Fsutil_HandleFetchType(Fspdev_ClientIOHandle, fileIDPtr);
  1872.     if (cltHandlePtr == (Fspdev_ClientIOHandle *)NIL) {
  1873.     printf( "FspdevPseudoStreamSetIOAttr, no handle <%d,%d,%x,%x>\n",
  1874.         fileIDPtr->serverID, fileIDPtr->type,
  1875.         fileIDPtr->major, fileIDPtr->minor);
  1876.     return(FS_FILE_NOT_FOUND);
  1877.     }
  1878.     Fsutil_HandleRelease(cltHandlePtr, TRUE);
  1879.     pdevHandlePtr = cltHandlePtr->pdevHandlePtr;
  1880.     LOCK_MONITOR;
  1881.     if (flags & FS_SET_TIMES) {
  1882.     pdevHandlePtr->ctrlHandlePtr->accessTime = attrPtr->accessTime.seconds;
  1883.     pdevHandlePtr->ctrlHandlePtr->modifyTime = attrPtr->dataModifyTime.seconds;
  1884.     }
  1885.     UNLOCK_MONITOR;
  1886.     return(SUCCESS);
  1887. }
  1888.  
  1889. /*
  1890.  *----------------------------------------------------------------------
  1891.  *
  1892.  * FspdevPseudoStreamRead --
  1893.  *
  1894.  *    Read from a pseudo-device stream. If there is data in the read
  1895.  *    ahead buffer (if one exists), that is used to satisfy the read.
  1896.  *    Otherwise a request-response exchange with the server is used
  1897.  *    to do the read.
  1898.  *
  1899.  * Results:
  1900.  *    SUCCESS, and *lenPtr reflects how much was read.  When the server
  1901.  *    goes away EOF is simulated by a SUCCESS return and *lenPtr == 0.
  1902.  *    If there is no data in the read ahead buffer FS_WOULD_BLOCK is returned.
  1903.  *
  1904.  * Side effects:
  1905.  *    If applicable, pointers into the read ahead buffer are adjusted.
  1906.  *    The buffer is filled with the number of bytes indicated by
  1907.  *    the length parameter.  The in/out length parameter specifies
  1908.  *    the buffer size on input and is updated to reflect the number
  1909.  *    of bytes actually read.
  1910.  *
  1911.  *----------------------------------------------------------------------
  1912.  */
  1913.  
  1914. ReturnStatus
  1915. FspdevPseudoStreamRead(streamPtr, readPtr, waitPtr, replyPtr)
  1916.     register Fs_Stream     *streamPtr;    /* Stream to read from. */
  1917.     Fs_IOParam        *readPtr;    /* Read parameter block. */
  1918.     Sync_RemoteWaiter    *waitPtr;    /* Process info for remote waiting */
  1919.     Fs_IOReply        *replyPtr;    /* Signal to return, if any,
  1920.                      * plus the amount read. */
  1921. {
  1922.     ReturnStatus     status;
  1923.     register Fspdev_ClientIOHandle *cltHandlePtr =
  1924.         (Fspdev_ClientIOHandle *)streamPtr->ioHandlePtr;
  1925.     register Fspdev_ServerIOHandle *pdevHandlePtr = cltHandlePtr->pdevHandlePtr;
  1926.     Pdev_Request    request;
  1927.  
  1928.     LOCK_MONITOR;
  1929.     while (pdevHandlePtr->flags & PDEV_BUSY) {
  1930.     if ((pdevHandlePtr->flags & PDEV_SERVER_GONE) == 0) {
  1931.         (void)Sync_Wait(&pdevHandlePtr->access, FALSE);
  1932.     }
  1933.     if (pdevHandlePtr->flags & PDEV_SERVER_GONE) {
  1934.         status = DEV_OFFLINE;
  1935.         goto exitNoServer;
  1936.     }
  1937.     }
  1938.     pdevHandlePtr->flags |= PDEV_BUSY;
  1939.  
  1940. #ifdef notdef
  1941.     {
  1942.     register Ioc_Owner *ownerPtr;
  1943.     /*
  1944.      * Check for access inside the owning process group.
  1945.      */
  1946.     ownerPtr = &pdevHandlePtr->ctrlHandlePtr->owner;
  1947.     if (((ownerPtr->procOrFamily == IOC_OWNER_FAMILY) &&
  1948.          (readPtr->familyID != ownerPtr->id)) ||
  1949.         ((ownerPtr->procOrFamily == IOC_OWNER_PROC) &&
  1950.          (readPtr->procID != ownerPtr->id))) {
  1951.         printf("PdevRead: ownership conflict\n");
  1952.         status = GEN_ABORTED_BY_SIGNAL;
  1953.         replyPtr->signal = SIG_TTY_INPUT;
  1954.         goto exit;
  1955.     }
  1956.     }
  1957. #endif
  1958.  
  1959.     if (pdevHandlePtr->readBuf.data != (Address)NIL) {
  1960.     /*
  1961.      * A read ahead buffer exists so we get data from it.  If it's
  1962.      * empty we put the client on the client I/O handle read wait list.
  1963.      */
  1964.     if (pdevHandlePtr->flags & PDEV_READ_BUF_EMPTY) {
  1965.         status = FS_WOULD_BLOCK;
  1966.         Fsutil_FastWaitListInsert(&pdevHandlePtr->cltReadWaitList, waitPtr);
  1967.         PDEV_TRACE(&pdevHandlePtr->hdr.fileID, PDEVT_READ_WAIT);
  1968.         DBG_PRINT( ("PDEV %x,%x Read (%d) Blocked\n", 
  1969.             streamPtr->ioHandlePtr->fileID.major,
  1970.             streamPtr->ioHandlePtr->fileID.minor,
  1971.             readPtr->length) );
  1972.         replyPtr->length = 0;
  1973.     } else {
  1974.         register int dataAvail, firstByte, lastByte, toRead;
  1975.         register Proc_ControlBlock *serverProcPtr;
  1976.  
  1977.         firstByte = pdevHandlePtr->readBuf.firstByte;
  1978.         lastByte = pdevHandlePtr->readBuf.lastByte;
  1979.         dataAvail = lastByte - firstByte + 1;
  1980.         if (dataAvail <= 0) {
  1981.         panic("FspdevPseudoStreamRead, dataAvail in read buf <= 0 bytes\n");
  1982.         status = DEV_OFFLINE;
  1983.         goto exit;
  1984.         }
  1985.         /*
  1986.          * Lock down the server process in preparation for copying
  1987.          * from the read ahead buffer.
  1988.          */
  1989.         serverProcPtr = Proc_LockPID(pdevHandlePtr->serverPID);
  1990.         if (serverProcPtr == (Proc_ControlBlock *)NIL) {
  1991.         status = DEV_OFFLINE;
  1992.         goto exit;
  1993.         }
  1994.         /*
  1995.          * Decide how much to read and note if we empty the buffer.
  1996.          */
  1997.         if (dataAvail > readPtr->length) {
  1998.         toRead = readPtr->length;
  1999.         } else {
  2000.         toRead = dataAvail;
  2001.         pdevHandlePtr->flags |= PDEV_READ_BUF_EMPTY;
  2002.         }
  2003.         DBG_PRINT( ("PDEV %x,%x Read %d Avail %d\n", 
  2004.             pdevHandlePtr->hdr.fileID.major,
  2005.             pdevHandlePtr->hdr.fileID.minor,
  2006.             toRead, dataAvail) );
  2007.         /*
  2008.          * Copy out of the read ahead buffer to the client's buffer.
  2009.          */
  2010.         status = Vm_CopyInProc(toRead, serverProcPtr,
  2011.               pdevHandlePtr->readBuf.data + firstByte,
  2012.               readPtr->buffer, (readPtr->flags & FS_USER) == 0);
  2013.         Proc_Unlock(serverProcPtr);
  2014.         /*
  2015.          * Update pointers and poke the server so it can find out.
  2016.          */
  2017.         replyPtr->length = toRead;
  2018.         pdevHandlePtr->readBuf.firstByte = firstByte + toRead;
  2019.         pdevHandlePtr->flags |= PDEV_READ_PTRS_CHANGED;
  2020.         Fsutil_FastWaitListNotify(&pdevHandlePtr->srvReadWaitList);
  2021.     }
  2022.     } else if (pdevHandlePtr->selectBits & FS_READABLE) {
  2023.     /*
  2024.      * No read ahead buffer and the state is readable.
  2025.      * Set up and do the request-response exchange.
  2026.      */
  2027.     request.hdr.operation        = PDEV_READ;
  2028.     request.param.read        = *readPtr;
  2029.  
  2030.     if (readPtr->flags & FS_USER) {
  2031.         pdevHandlePtr->flags |= FS_USER_OUT;
  2032.     }
  2033.     status = RequestResponse(pdevHandlePtr, sizeof(Pdev_Request),
  2034.         &request.hdr, 0, (Address) NIL, readPtr->length, readPtr->buffer,
  2035.             replyPtr, waitPtr);
  2036.     } else {
  2037.     /*
  2038.      * The pseudo-device is not readable now.
  2039.      */
  2040.     Fsutil_FastWaitListInsert(&pdevHandlePtr->cltReadWaitList, waitPtr);
  2041.     replyPtr->length = 0;
  2042.     status = FS_WOULD_BLOCK;
  2043.     }
  2044.     if (status == SUCCESS) {
  2045.     pdevHandlePtr->ctrlHandlePtr->accessTime = Fsutil_TimeInSeconds();
  2046.     }
  2047. exit:
  2048.     if (status == DEV_OFFLINE) {
  2049.     /*
  2050.      * Simulate EOF
  2051.      */
  2052.     status = SUCCESS;
  2053.     replyPtr->length = 0;
  2054.     }
  2055.     pdevHandlePtr->flags &= ~(PDEV_BUSY|FS_USER_OUT);
  2056. exitNoServer:
  2057.     Sync_Broadcast(&pdevHandlePtr->access);
  2058.     UNLOCK_MONITOR;
  2059.     return(status);
  2060. }
  2061.  
  2062. /*
  2063.  *----------------------------------------------------------------------
  2064.  *
  2065.  * FspdevPseudoStreamWrite --
  2066.  *
  2067.  *    Write to a pseudo-device by a client.  The write is done
  2068.  *    asynchronously if the stream allows that.  In that case we
  2069.  *    always say we could write as much as requested.  However, if
  2070.  *    the write is larger than the server's request buffer we
  2071.  *    break it into blocks that each fit. To support UDP, the
  2072.  *    stream can also be marked to dis-allow these large writes.
  2073.  *    Finally, the stream may be marked synchronous in which case
  2074.  *    we tell RequestResponse to wait for a reply.
  2075.  *
  2076.  * Results:
  2077.  *    SUCCESS            - the data was written.
  2078.  *
  2079.  * Side effects:
  2080.  *    The data in the buffer is written to the device.  Large writes
  2081.  *    are broken into a series of shorter writes, although we keep
  2082.  *    the access lock on the pseudo-stream so the whole write completes.
  2083.  *    The in/out length parameter specifies the amount of data to write
  2084.  *    and is updated to reflect the number of bytes actually written.
  2085.  *
  2086.  *----------------------------------------------------------------------
  2087.  */
  2088. ENTRY ReturnStatus
  2089. FspdevPseudoStreamWrite(streamPtr, writePtr, waitPtr, replyPtr)
  2090.     Fs_Stream     *streamPtr;    /* Stream to write to. */
  2091.     Fs_IOParam        *writePtr;    /* Read parameter block */
  2092.     Sync_RemoteWaiter    *waitPtr;    /* Process info for remote waiting */
  2093.     Fs_IOReply        *replyPtr;    /* Signal to return, if any */
  2094. {
  2095.     register Fspdev_ClientIOHandle *cltHandlePtr =
  2096.         (Fspdev_ClientIOHandle *)streamPtr->ioHandlePtr;
  2097.     register Fspdev_ServerIOHandle *pdevHandlePtr = cltHandlePtr->pdevHandlePtr;
  2098.     ReturnStatus     status = SUCCESS;
  2099.     Pdev_Request    request;
  2100.     int            amountWritten;
  2101.     int            numBytes;
  2102.     int            maxRequestSize;
  2103.     int            totalToWrite;
  2104.  
  2105.     LOCK_MONITOR;
  2106.     /*
  2107.      * Wait for exclusive access to the stream.
  2108.      */
  2109.     while (pdevHandlePtr->flags & PDEV_BUSY) {
  2110.     if ((pdevHandlePtr->flags & PDEV_SERVER_GONE) == 0) {
  2111.         (void)Sync_Wait(&pdevHandlePtr->access, FALSE);
  2112.     }
  2113.     if (pdevHandlePtr->flags & PDEV_SERVER_GONE) {
  2114.         status = FS_BROKEN_PIPE;
  2115.         goto exitNoServer;
  2116.     }
  2117.     }
  2118.     pdevHandlePtr->flags |= PDEV_BUSY;
  2119.     if (writePtr->flags & FS_USER) {
  2120.     pdevHandlePtr->flags |= FS_USER_IN;
  2121.     }
  2122.  
  2123. #ifdef notdef
  2124.     {
  2125.     /*
  2126.      * Check for access inside the owning process group.
  2127.      * (This doesn't work presently, 6/89.  We'll rely on
  2128.      * the tty driver to do this checking for us.)
  2129.      *
  2130.      * Getting 4.3 BSD semantics is tricky because the operation is
  2131.      * supposed to succeed if the TTYOUT signal is blocked. Need a
  2132.      * flag passed down from Fs_Write.
  2133.      */
  2134.     Ioc_Owner        *ownerPtr;
  2135.     ownerPtr = &pdevHandlePtr->ctrlHandlePtr->owner;
  2136.     if (((ownerPtr->procOrFamily == IOC_OWNER_FAMILY) &&
  2137.          (writePtr->familyID != ownerPtr->id)) ||
  2138.         ((ownerPtr->procOrFamily == IOC_OWNER_PROC) &&
  2139.          (writePtr->procID != ownerPtr->id))) {
  2140.         printf("PdevWrite: ownership conflict\n");
  2141.         status = GEN_ABORTED_BY_SIGNAL;
  2142.         replyPtr->signal = SIG_TTY_OUTPUT;
  2143.         goto exit;
  2144.     }
  2145.     }
  2146. #endif
  2147.     /*
  2148.      * Allow flow control by checking the select bits and only trying
  2149.      * the operation if the state allows it.
  2150.      */
  2151.     if ((pdevHandlePtr->selectBits & FS_WRITABLE) == 0) {
  2152.     replyPtr->length = 0;
  2153.     Fsutil_FastWaitListInsert(&pdevHandlePtr->cltWriteWaitList, waitPtr);
  2154.     status = FS_WOULD_BLOCK;
  2155.     goto exit;
  2156.     }
  2157.  
  2158.     maxRequestSize = pdevHandlePtr->requestBuf.size - sizeof(Pdev_Request);
  2159.     if (writePtr->length > maxRequestSize &&
  2160.     (pdevHandlePtr->flags & PDEV_NO_BIG_WRITES)) {
  2161.     printf("Too large a write (%d bytes) an a (UDP?) pseudo-device\n",
  2162.         writePtr->length);
  2163.     status = GEN_INVALID_ARG;
  2164.     goto exit;
  2165.     }
  2166.  
  2167.     if (pdevHandlePtr->flags & PDEV_WRITE_BEHIND) {
  2168.     request.hdr.operation        = PDEV_WRITE_ASYNC;
  2169.     } else {
  2170.     request.hdr.operation        = PDEV_WRITE;
  2171.     }
  2172.     request.param.write            = *writePtr;
  2173.     request.param.write.buffer        = 0;
  2174.  
  2175.     amountWritten = 0;
  2176.     totalToWrite = writePtr->length;
  2177.     while ((writePtr->length > 0) && (status == SUCCESS)) {
  2178.     /*
  2179.      * Loop to put the maximum amount of data into the request
  2180.      * buffer until the whole block has been transferred.  The
  2181.      * server returns an int, the number of bytes it accepted.
  2182.      */
  2183.     request.param.write.length = (writePtr->length > maxRequestSize) ?
  2184.                       maxRequestSize : writePtr->length;
  2185.     request.param.write.offset = writePtr->offset + amountWritten;
  2186.     status = RequestResponse(pdevHandlePtr, sizeof(Pdev_Request),
  2187.                  &request.hdr, request.param.write.length,
  2188.                  writePtr->buffer + amountWritten,
  2189.                  sizeof(int), (Address)&numBytes,
  2190.                  replyPtr, waitPtr);
  2191.     if (pdevHandlePtr->flags & PDEV_WRITE_BEHIND) {
  2192.         /*
  2193.          * Assume all bytes accepted when write-behind is enabled.
  2194.          */
  2195.         numBytes = request.param.write.length;
  2196.     } else if (replyPtr->length != sizeof(int)) {
  2197.         numBytes = 0;
  2198.     }
  2199.     amountWritten += numBytes;
  2200.     writePtr->length -= numBytes;
  2201.     }
  2202.     if (amountWritten > totalToWrite) {
  2203.     printf("FspdevPseudoStreamWrite: \"%s\" amount written (%d) > requested (%d)\n",
  2204.         Fsutil_HandleName(streamPtr->ioHandlePtr), amountWritten, totalToWrite);
  2205.     amountWritten = totalToWrite;
  2206.     }
  2207.     replyPtr->length = amountWritten;
  2208.     if (amountWritten > 0) {
  2209.     pdevHandlePtr->ctrlHandlePtr->modifyTime = Fsutil_TimeInSeconds();
  2210.     }
  2211. exit:
  2212.     if (status == DEV_OFFLINE) {
  2213.     /*
  2214.      * Simulate a broken pipe so writers die.
  2215.      */
  2216.     replyPtr->signal = SIG_PIPE;
  2217.     status = FS_BROKEN_PIPE;
  2218.     }
  2219.     if (replyPtr->signal != 0) {
  2220.     printf("PdevWrite: signal %d\n", replyPtr->signal);
  2221.     }
  2222.     pdevHandlePtr->flags &= ~(PDEV_BUSY|FS_USER_IN);
  2223. exitNoServer:
  2224.     Sync_Broadcast(&pdevHandlePtr->access);
  2225.     UNLOCK_MONITOR;
  2226.     return(status);
  2227. }
  2228.  
  2229. /*
  2230.  *----------------------------------------------------------------------
  2231.  *
  2232.  * FspdevPseudoStreamIOControl --
  2233.  *
  2234.  *    IOControls for pseudo-device.  The in parameter block of the
  2235.  *    IOControl is passed to the server, and its response is used
  2236.  *    to fill the return parameter block of the client.
  2237.  *
  2238.  * Results:
  2239.  *    SUCCESS            - the operation was successful.
  2240.  *
  2241.  * Side effects:
  2242.  *    None here in the kernel, anyway.
  2243.  *
  2244.  *----------------------------------------------------------------------
  2245.  */
  2246.  
  2247. ReturnStatus
  2248. FspdevPseudoStreamIOControl(streamPtr, ioctlPtr, replyPtr)
  2249.     Fs_Stream    *streamPtr;    /* Stream to pseudo-device */
  2250.     Fs_IOCParam *ioctlPtr;    /* Standard I/O Control parameter block */
  2251.     Fs_IOReply *replyPtr;    /* Output buffer length and signal to return */
  2252. {
  2253.     ReturnStatus     status;
  2254.     Pdev_Request    request;
  2255.     register Fspdev_ClientIOHandle *cltHandlePtr =
  2256.         (Fspdev_ClientIOHandle *)streamPtr->ioHandlePtr;
  2257.     register Fspdev_ServerIOHandle *pdevHandlePtr = cltHandlePtr->pdevHandlePtr;
  2258.     Boolean    sendToServer;
  2259.  
  2260.     LOCK_MONITOR;
  2261.     /*
  2262.      * Wait for exclusive access to the stream.
  2263.      */
  2264.     while (pdevHandlePtr->flags & PDEV_BUSY) {
  2265.     if ((pdevHandlePtr->flags & PDEV_SERVER_GONE) == 0) {
  2266.         (void)Sync_Wait(&pdevHandlePtr->access, FALSE);
  2267.     }
  2268.     if (pdevHandlePtr->flags & PDEV_SERVER_GONE) {
  2269.         status = DEV_OFFLINE;
  2270.         goto exit;
  2271.     }
  2272.     }
  2273.     pdevHandlePtr->flags |= PDEV_BUSY;
  2274.  
  2275.     /*
  2276.      * Decide if the buffers are already in the kernel or not.  The buffers
  2277.      * for generic I/O controls are copied in, and if we are being called
  2278.      * from an RPC stub they are also in kernel space.
  2279.      */
  2280.     if (ioctlPtr->flags & FS_USER_IN) {
  2281.     pdevHandlePtr->flags |= FS_USER_IN;
  2282.     }
  2283.     if (ioctlPtr->flags & FS_USER_OUT) {
  2284.     pdevHandlePtr->flags |= FS_USER_OUT;
  2285.     }
  2286.  
  2287.     status = SUCCESS;
  2288.     sendToServer = TRUE;
  2289.  
  2290.     if (ioctlPtr->command == IOC_NUM_READABLE &&
  2291.     pdevHandlePtr->readBuf.data != (Address)NIL) {
  2292.     /*
  2293.      * Trap out the IOC_NUM_READABLE if there's a read ahead buf.
  2294.      */
  2295.     int bytesAvail;
  2296.     if (pdevHandlePtr->flags & PDEV_READ_BUF_EMPTY) {
  2297.         bytesAvail = 0;
  2298.     } else {
  2299.         bytesAvail = pdevHandlePtr->readBuf.lastByte -
  2300.              pdevHandlePtr->readBuf.firstByte + 1;
  2301.     }
  2302.     if (ioctlPtr->outBufSize != sizeof(int)) {
  2303.         status = GEN_INVALID_ARG;
  2304.     } else if (ioctlPtr->format != mach_Format) {
  2305.         int size = sizeof(int);
  2306.         int inSize = sizeof(int);
  2307.         int fmtStatus;
  2308.         fmtStatus = Fmt_Convert("w", mach_Format, &inSize, 
  2309.                 (Address) &bytesAvail,
  2310.                 ioctlPtr->format, &size, ioctlPtr->outBuffer);
  2311.         if (fmtStatus != 0) {
  2312.         printf("Format of ioctl failed <0x%x>\n", fmtStatus);
  2313.         status = GEN_INVALID_ARG;
  2314.         }
  2315.         if (size != sizeof(int)) {
  2316.         status = GEN_INVALID_ARG;
  2317.         }
  2318.     } else {
  2319.         *(int *)ioctlPtr->outBuffer = bytesAvail;
  2320.     }
  2321.     DBG_PRINT( ("IOC  %x,%x num readable %d\n",
  2322.         pdevHandlePtr->hdr.fileID.major,
  2323.         pdevHandlePtr->hdr.fileID.minor,
  2324.         bytesAvail) );
  2325.     } else {
  2326.     /*
  2327.      * Switch out on command for any special processing,
  2328.      * then do a request-response transaction with the server.
  2329.      */
  2330.     switch(ioctlPtr->command) {
  2331.         case IOC_SET_OWNER: {
  2332.         /*
  2333.          * Siphon off the ownership so we can enforce it in the kernel.
  2334.          */
  2335.         if (ioctlPtr->inBufSize < sizeof(Ioc_Owner)) {
  2336.             status = GEN_INVALID_ARG;
  2337.         } else {
  2338.             pdevHandlePtr->ctrlHandlePtr->owner =
  2339.                 *(Ioc_Owner *)ioctlPtr->inBuffer;
  2340.         }
  2341.         break;
  2342.         }
  2343.         case IOC_GET_OWNER: {
  2344.         /*
  2345.          * Do our own get owner, but let the server see the request.
  2346.          */
  2347.         if (ioctlPtr->outBufSize < sizeof(Ioc_Owner)) {
  2348.             status = GEN_INVALID_ARG;
  2349.         } else {
  2350.             *(Ioc_Owner *)ioctlPtr->outBuffer =
  2351.                 pdevHandlePtr->ctrlHandlePtr->owner;
  2352.         }
  2353.         break;
  2354.         }
  2355.         case IOC_PREFIX: 
  2356.         status = SUCCESS;
  2357.         sendToServer = FALSE;
  2358.         break;
  2359.     }
  2360.     if (status == SUCCESS && sendToServer) {
  2361.         request.hdr.operation    = PDEV_IOCTL;
  2362.         request.param.ioctl        = *ioctlPtr;
  2363.  
  2364.         status = RequestResponse(pdevHandlePtr, sizeof(Pdev_Request),
  2365.                  &request.hdr,
  2366.                  ioctlPtr->inBufSize, ioctlPtr->inBuffer,
  2367.                  ioctlPtr->outBufSize, ioctlPtr->outBuffer,
  2368.                  replyPtr, (Sync_RemoteWaiter *)NIL);
  2369.     }
  2370.     }
  2371.  
  2372.     pdevHandlePtr->flags &= ~(PDEV_BUSY|FS_USER_IN|FS_USER_OUT);
  2373. exit:
  2374.     Sync_Broadcast(&pdevHandlePtr->access);
  2375.     UNLOCK_MONITOR;
  2376.     return(status);
  2377. }
  2378.  
  2379.  
  2380. /*
  2381.  *----------------------------------------------------------------------
  2382.  *
  2383.  * FspdevPseudoStreamSelect --
  2384.  *
  2385.  *    Select on a pseudo-device.  This is done by checking the stream
  2386.  *    state kept on the host of the server.  If the pseudo device isn't
  2387.  *    selectable we just return and let the server's IOC_PDEV_READY
  2388.  *    IOControl do the wakeup for us. (ie. we don't use the handle wait
  2389.  *    lists.)
  2390.  *
  2391.  * Results:
  2392.  *    SUCCESS    or FS_WOULD_BLOCK
  2393.  *
  2394.  * Side effects:
  2395.  *    *outFlagsPtr modified to indicate whether the device is
  2396.  *    readable or writable.
  2397.  *
  2398.  *----------------------------------------------------------------------
  2399.  */
  2400.  
  2401. ReturnStatus
  2402. FspdevPseudoStreamSelect(hdrPtr, waitPtr, readPtr, writePtr, exceptPtr)
  2403.     Fs_HandleHeader    *hdrPtr;    /* Handle on pdev to select */
  2404.     Sync_RemoteWaiter    *waitPtr;    /* Process info for remote waiting */
  2405.     int         *readPtr;    /* Bit to clear if non-readable */
  2406.     int         *writePtr;    /* Bit to clear if non-writeable */
  2407.     int         *exceptPtr;    /* Bit to clear if non-exceptable */
  2408. {
  2409.     ReturnStatus status;
  2410.     register Fspdev_ClientIOHandle *cltHandlePtr = (Fspdev_ClientIOHandle *)hdrPtr;
  2411.     register Fspdev_ServerIOHandle *pdevHandlePtr = cltHandlePtr->pdevHandlePtr;
  2412.  
  2413.     LOCK_MONITOR;
  2414.  
  2415.     PDEV_TSELECT(&cltHandlePtr->hdr.fileID, *readPtr, *writePtr, *exceptPtr);
  2416.  
  2417.     if ((pdevHandlePtr->flags & PDEV_SERVER_GONE) ||
  2418.     (pdevHandlePtr->flags & PDEV_SETUP) == 0) {
  2419.     status = DEV_OFFLINE;
  2420.     } else {
  2421.     if (*readPtr) {
  2422.         if (((pdevHandlePtr->readBuf.data == (Address)NIL) &&
  2423.          ((pdevHandlePtr->selectBits & FS_READABLE) == 0)) ||
  2424.         ((pdevHandlePtr->readBuf.data != (Address)NIL) &&
  2425.          (pdevHandlePtr->flags & PDEV_READ_BUF_EMPTY))) {
  2426.         *readPtr = 0;
  2427.         if (waitPtr != (Sync_RemoteWaiter *)NIL) {
  2428.             Fsutil_FastWaitListInsert(&pdevHandlePtr->cltReadWaitList,
  2429.                     waitPtr);
  2430.         }
  2431.         }
  2432.     }
  2433.     if (*writePtr && ((pdevHandlePtr->selectBits & FS_WRITABLE) == 0)) {
  2434.         *writePtr = 0;
  2435.         if (waitPtr != (Sync_RemoteWaiter *)NIL) {
  2436.         Fsutil_FastWaitListInsert(&pdevHandlePtr->cltWriteWaitList, waitPtr);
  2437.         }
  2438.     }    
  2439.     if (*exceptPtr && ((pdevHandlePtr->selectBits & FS_EXCEPTION) == 0)) {
  2440.             *exceptPtr = 0;
  2441.         if (waitPtr != (Sync_RemoteWaiter *)NIL) {
  2442.         Fsutil_FastWaitListInsert(&pdevHandlePtr->cltExceptWaitList,waitPtr);
  2443.         }
  2444.     }
  2445.     status = SUCCESS;
  2446.     }
  2447.     UNLOCK_MONITOR;
  2448.     return(status);
  2449. }
  2450.  
  2451.  
  2452. /*
  2453.  *----------------------------------------------------------------------
  2454.  *
  2455.  * PdevClientNotify --
  2456.  *
  2457.  *    Wakeup any processes selecting or blocking on the pseudo-stream.
  2458.  *
  2459.  * Results:
  2460.  *    None.
  2461.  *
  2462.  * Side effects:
  2463.  *    None.
  2464.  *
  2465.  *----------------------------------------------------------------------
  2466.  */
  2467.  
  2468. INTERNAL static void
  2469. PdevClientNotify(pdevHandlePtr)
  2470.     Fspdev_ServerIOHandle *pdevHandlePtr;
  2471. {
  2472.     register int selectBits = pdevHandlePtr->selectBits;
  2473.  
  2474.     PDEV_WAKEUP(&pdevHandlePtr->hdr.fileID, pdevHandlePtr->clientPID,
  2475.         pdevHandlePtr->selectBits);
  2476.     if (selectBits & FS_READABLE) {
  2477.     Fsutil_FastWaitListNotify(&pdevHandlePtr->cltReadWaitList);
  2478.     }
  2479.     if (selectBits & FS_WRITABLE) {
  2480.     Fsutil_FastWaitListNotify(&pdevHandlePtr->cltWriteWaitList);
  2481.     }
  2482.     if (selectBits & FS_EXCEPTION) {
  2483.     Fsutil_FastWaitListNotify(&pdevHandlePtr->cltExceptWaitList);
  2484.     }
  2485. }
  2486.  
  2487. /*
  2488.  *----------------------------------------------------------------------
  2489.  *
  2490.  * FspdevPseudoStreamCloseInt --
  2491.  *
  2492.  *    Do a close request-response with the server.
  2493.  *
  2494.  * Results:
  2495.  *    None.
  2496.  *
  2497.  * Side effects:
  2498.  *    None.
  2499.  *
  2500.  *----------------------------------------------------------------------
  2501.  */
  2502.  
  2503. ENTRY void
  2504. FspdevPseudoStreamCloseInt(pdevHandlePtr)
  2505.     register Fspdev_ServerIOHandle *pdevHandlePtr;
  2506. {
  2507.     Pdev_Request    request;
  2508.  
  2509.     LOCK_MONITOR;
  2510.  
  2511.     while (pdevHandlePtr->flags & PDEV_BUSY) {
  2512.     if ((pdevHandlePtr->flags & PDEV_SERVER_GONE) == 0) {
  2513.         (void)Sync_Wait(&pdevHandlePtr->access, FALSE);
  2514.     }
  2515.     if (pdevHandlePtr->flags & PDEV_SERVER_GONE) {
  2516.         goto exit;
  2517.     }
  2518.     }
  2519.     pdevHandlePtr->flags |= PDEV_BUSY;
  2520.     /*
  2521.      * Someday we could set up a timeout call-back here in case
  2522.      * the server never replies.
  2523.      */
  2524.     request.hdr.operation = PDEV_CLOSE;
  2525.     (void) RequestResponse(pdevHandlePtr, sizeof(Pdev_Request), &request.hdr,
  2526.             0, (Address)NIL, 0, (Address)NIL, (Fs_IOReply *) NIL,
  2527.             (Sync_RemoteWaiter *)NIL);
  2528.     pdevHandlePtr->flags &= ~(PDEV_BUSY|FS_USER);
  2529. exit:
  2530.     Sync_LockClear(&pdevHandlePtr->lock);
  2531.     Sync_Broadcast(&pdevHandlePtr->access);
  2532.     UNLOCK_MONITOR;
  2533. }
  2534.